Skip to content

Instantly share code, notes, and snippets.

@SysPete
Created March 27, 2014 20:34
Show Gist options
  • Save SysPete/9817984 to your computer and use it in GitHub Desktop.
Save SysPete/9817984 to your computer and use it in GitHub Desktop.
old TaxZone.pm
use utf8;
package Interchange6::Schema::Result::TaxRule;
=head1 NAME
Interchange6::Schema::Result::TaxRule
=cut
use strict;
use warnings;
use DateTime;
use base 'DBIx::Class::Core';
# to enable code references to be serialized
$Storable::Deparse = 1;
$Storable::Eval = 1;
# component load order is important so be careful here:
__PACKAGE__->load_components(
qw(InflateColumn::Serializer InflateColumn::DateTime TimeStamp));
=head1 TABLE: C<tax_rules>
=cut
__PACKAGE__->table("tax_rules");
=head1 DESCRIPTION
=head1 ACCESSORS
=head2 tax_rules_id
data_type: 'integer'
is_auto_increment: 1
is_nullable: 0
sequence: 'tax_rules_id_seq'
=head2 name
data_type: 'varchar'
is_nullable: 0
size: 64
=head2 priority
data_type: integer
is_nullable: 0
default: 0
=head2 last_rule
data_type: boolean
is_nullable: 0
default: 1
=head2 supplier_zone
data_type: integer
is_nullable: 0
=head2 customer_zone
data_type: integer
is_nullable: 0
=head2 business_customer
data_type: boolean
is_nullable: 1
default: undef
=head2 product_type
data_type: varchar
is_nullable: 1
size: 64
=head2 tax_code
data_type: 'varchar'
is_nullable: 0
size: 64
=head2 valid_from
data_type: 'date'
set_on_create: 1
is_nullable: 0
=head2 valid_to
data_type: 'date'
is_nullable: 1
=head2 coderef_rule
data_type: 'varchar'
size: 1024
serializer_class: 'Storable'
is_nullable: 1
WARNING: Here be dragons. If you think you need to use coderef_rule then make sure you have tested it thoroughly. This method might eat your cat and burn down your house. Do not run as root! See t/taxes.t in the distribution source for examples.
=cut
__PACKAGE__->add_columns(
"tax_rules_id",
{
data_type => "integer",
is_auto_increment => 1,
is_nullable => 0,
sequence => "taxes_id_seq"
},
"name",
{ data_type => "varchar", is_nullable => 0, size => 64 },
"priority",
{ data_type => "integer", is_nullable => 0, default => 0 },
"last_rule",
{ data_type => "boolean", is_nullable => 0, default => 1 },
"supplier_zone",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"customer_zone",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"business_customer",
{ data_type => "boolean", is_nullable => 1, default => undef },
"product_type",
{ data_type => "varchar", is_nullable => 1, size => 64 },
"tax_code",
{ data_type => "varchar", is_nullable => 0, size => 64 },
"valid_from",
{ data_type => "date", set_on_create => 1, is_nullable => 0 },
"valid_to",
{ data_type => "date", is_nullable => 1 },
"coderef_rule",
{
data_type => "varchar",
size => 1024,
serializer_class => "Storable",
is_nullable => 1
},
);
=head1 METHODS
=head1 PRIMARY KEY
=over 4
=item * L</tax_rules_id>
=back
=cut
__PACKAGE__->set_primary_key("tax_rules_id");
=head1 RELATIONS
=head2 supplier_zone
Type: belongs_to
=cut
__PACKAGE__->belongs_to(
"supplier_zone",
"Interchange6::Schema::Result::TaxZone",
{ "foreign.tax_zones_id" => "self.supplier_zone" }
);
=head2 customer_zone
Type: belongs_to
=cut
__PACKAGE__->belongs_to(
"customer_zone",
"Interchange6::Schema::Result::TaxZone",
{ "foreign.tax_zones_id" => "self.customer_zone" }
);
1;
use utf8;
package Interchange6::Schema::ResultSet::TaxRule;
=head1 NAME
Interchange6::Schema::ResultSet::TaxRule
=cut
=head1 SYNOPSIS
Provides extra accessor methods for L<Interchange6::Schema::Result::TaxRule>
=cut
use strict;
use warnings;
use Moo;
extends 'DBIx::Class::ResultSet';
with('Interchange6::Schema::Role::Errors');
use DateTime;
use MooX::Types::MooseLike;
use MooX::Types::MooseLike::Base qw/ArrayRef HashRef/;
use MooX::HandlesVia;
use namespace::clean;
=head1 METHODS
=head2 taxes
Should not be called directly - use get_taxes method.
=cut
has taxes => (
is => 'ro',
isa => ArrayRef [HashRef],
default => sub { [] },
handles_via => 'Array',
handles => {
clear_taxes => 'clear',
_add_tax => 'push',
is_empty => 'is_empty',
}
);
=head2 get_taxes
When passed a hashref of args it returns an arrayref of taxes.
Arguments:
=over 4
item * supplier_zone name - required
item * customer_zone name - required
item * price - required
item * product_type - optional
item * business_customer (boolean) - optional
item * tax_included (boolean) - optional with default 0
item * business_customer (boolean) - optional with default 0
=back
=cut
sub get_taxes {
my ( $self, $args ) = @_;
$self->clear_errors;
$self->clear_taxes;
my @return;
my $schema = $self->result_source->schema;
my $dtf = $schema->storage->datetime_parser;
my $dt = DateTime->today;
# set tax_included to 0 if not defined
$args->{'tax_included'} = 0 unless defined $args->{'tax_included'};
# check for required args
unless ( defined $args->{'supplier_country'} ) {
# supplier country must be defined
$self->add_error( "missing arg supplier_country" );
return;
}
unless ( defined $args->{'customer_country'} ) {
# customer country must be defined
$self->add_error( "missing arg customer_country" );
return;
}
unless ( defined $args->{'price'} ) {
# price country must be defined
$self->add_error( "missing arg price" );
return;
}
my $rules = $self->search(
{
valid_from => { '<=', $dtf->format_datetime($dt) },
valid_to => [ undef, { '>=', $dtf->format_datetime($dt) } ],
},
{ order_by => 'priority' }
);
RULES: while ( my $rule = $rules->next ) {
# start with checks that don't hit the DB
# check product_type
if ( defined $rule->product_type ) {
next RULES
unless ( defined $args->{'product_type'}
&& $args->{'product_type'} eq $rule->product_type );
}
# check business_customer
if ( defined $rule->business_customer ) {
# defined so does rule match arg?
$args->{'business_customer'} = 0
unless $args->{'business_customer'};
next RULES
unless $args->{'business_customer'} == $rule->business_customer;
}
# checks that might hit the DB from here on
# check supplier_country and supplier_state
if ( defined $rule->supplier_zone ) {
# rule has supplier_zone
# supplier_country must be in zone
next RULES
unless $rule->supplier_zone->has_country(
$args->{'supplier_country'} );
if ( $rule->supplier_zone->state_count ) {
# supplier_zone has states in it
# supplier_state must be defined and in zone
next RULES
unless (
defined $args->{'supplier_state'}
&& $rule->supplier_zone->has_state(
$args->{'supplier_state'}
)
);
}
}
# check customer_country and customer_state
if ( defined $rule->customer_zone ) {
# rule has customer_zone
# customer_country must be in zone
next RULES
unless $rule->customer_zone->has_country(
$args->{'customer_country'} );
if ( $rule->customer_zone->state_count ) {
# customer_zone has states in it
# customer_state must be defined and in zone
next RULES
unless (
defined $args->{'customer_state'}
&& $rule->customer_zone->has_state(
$args->{'customer_state'}
)
);
}
}
# coderef_rule - last thing before we work out the taxes
if ( defined $rule->coderef_rule ) {
my $coderef = $rule->coderef_rule;
next RULES unless &$coderef( $self, $args, $rule );
}
# if we got this far then this rule is applicable so work out the taxes
my $tax = $schema->resultset('Tax')->current_tax( $rule->tax_code );
unless ( defined $tax ) {
$self->add_error( "tax_code not found: " . $rule->tax_code );
return;
}
my $tax_amount = $tax->calculate(
{
price => $args->{'price'},
tax_included => $args->{'tax_included'}
}
);
$self->_add_tax(
{
tax_amount => $tax_amount,
tax_rule => $rule->name,
tax_code => $rule->tax_code,
tax_percent => $tax->tax_percent,
}
);
last RULES if $rule->last_rule;
}
return $self->taxes;
}
1;
@hexfusion
Copy link

Hexfusion was here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment