687 lines
21 KiB
Perl
687 lines
21 KiB
Perl
package Koha::Acquisition::Order;
|
|
|
|
# This file is part of Koha.
|
|
#
|
|
# Koha is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Koha is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Koha; if not, see <https://www.gnu.org/licenses>.
|
|
|
|
use Modern::Perl;
|
|
|
|
use Carp qw( croak );
|
|
|
|
use C4::Biblio qw( DelBiblio );
|
|
use C4::Acquisition;
|
|
use C4::Suggestions qw( ModSuggestion );
|
|
|
|
use Koha::Acquisition::Baskets;
|
|
use Koha::Acquisition::Funds;
|
|
use Koha::Acquisition::Invoices;
|
|
use Koha::Acquisition::Order::Claims;
|
|
use Koha::Database;
|
|
use Koha::DateUtils qw( dt_from_string );
|
|
use Koha::Exceptions::Object;
|
|
use Koha::Biblios;
|
|
use Koha::Holds;
|
|
use Koha::Items;
|
|
use Koha::Number::Price;
|
|
use Koha::Patrons;
|
|
use Koha::Subscriptions;
|
|
|
|
use base qw(Koha::Object Koha::Object::Mixin::AdditionalFields);
|
|
|
|
=head1 NAME
|
|
|
|
Koha::Acquisition::Order Object class
|
|
|
|
=head1 API
|
|
|
|
=head2 Class methods
|
|
|
|
=head3 new
|
|
|
|
Overloaded I<new> method for backwards compatibility.
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $self, $params ) = @_;
|
|
|
|
my $schema = Koha::Database->new->schema;
|
|
my @columns = $schema->source('Aqorder')->columns;
|
|
|
|
my $values =
|
|
{ map { exists $params->{$_} ? ( $_ => $params->{$_} ) : () } @columns };
|
|
return $self->SUPER::new($values);
|
|
}
|
|
|
|
=head3 store
|
|
|
|
Overloaded I<store> method for backwards compatibility.
|
|
|
|
=cut
|
|
|
|
sub store {
|
|
my ($self) = @_;
|
|
|
|
my $schema = Koha::Database->new->schema;
|
|
|
|
# Override quantity for standing orders
|
|
$self->quantity(1) if ( $self->basketno && $schema->resultset('Aqbasket')->find( $self->basketno )->is_standing );
|
|
|
|
# if these parameters are missing, we can't continue
|
|
for my $key (qw( basketno quantity biblionumber budget_id )) {
|
|
next
|
|
if $key eq 'biblionumber'
|
|
&& ( $self->orderstatus // q{} ) eq 'cancelled'; # cancelled order might have biblionumber NULL
|
|
croak "Cannot insert order: Mandatory parameter $key is missing"
|
|
unless $self->$key;
|
|
}
|
|
|
|
if ( not defined $self->{created_by} ) {
|
|
my $userenv = C4::Context->userenv;
|
|
if ($userenv) {
|
|
$self->created_by( $userenv->{number} );
|
|
}
|
|
}
|
|
|
|
$self->quantityreceived(0) unless $self->quantityreceived;
|
|
$self->entrydate(dt_from_string) unless $self->entrydate;
|
|
|
|
$self->ordernumber(undef) unless $self->ordernumber;
|
|
$self = $self->SUPER::store($self);
|
|
|
|
unless ( $self->parent_ordernumber ) {
|
|
$self->set( { parent_ordernumber => $self->ordernumber } );
|
|
$self = $self->SUPER::store($self);
|
|
}
|
|
|
|
return $self;
|
|
}
|
|
|
|
=head3 cancel
|
|
|
|
$order->cancel(
|
|
{
|
|
[
|
|
reason => $reason,
|
|
delete_biblio => $delete_biblio
|
|
]
|
|
}
|
|
);
|
|
|
|
This method marks an order as cancelled, optionally using the I<reason> parameter.
|
|
As the order is cancelled, the (eventual) items linked to it are removed.
|
|
If I<delete_biblio> is passed, it will try to remove the linked biblio.
|
|
|
|
If either the items or biblio removal fails, an error message is added to the object
|
|
so the caller can take appropriate actions.
|
|
|
|
=cut
|
|
|
|
sub cancel {
|
|
my ( $self, $params ) = @_;
|
|
|
|
my $delete_biblio = $params->{delete_biblio};
|
|
my $reason = $params->{reason};
|
|
|
|
# Delete the related items
|
|
my $items = $self->items;
|
|
while ( my $item = $items->next ) {
|
|
my $deleted = $item->safe_delete;
|
|
unless ($deleted) {
|
|
$self->add_message(
|
|
{
|
|
message => 'error_delitem',
|
|
payload => { item => $item, reason => @{ $deleted->messages }[0]->message }
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
# If ordered from a suggestion, revert the suggestion status to ACCEPTED
|
|
my $suggestion = Koha::Suggestions->find( { biblionumber => $self->biblionumber, status => "ORDERED" } );
|
|
if ( $suggestion and $suggestion->id ) {
|
|
ModSuggestion(
|
|
{
|
|
suggestionid => $suggestion->id,
|
|
biblionumber => $self->biblionumber,
|
|
STATUS => 'ACCEPTED',
|
|
}
|
|
);
|
|
}
|
|
|
|
my $biblio = $self->biblio;
|
|
if ( $biblio and $delete_biblio ) {
|
|
|
|
if ( $biblio->uncancelled_orders->search( { ordernumber => { '!=' => $self->ordernumber } } )->count == 0
|
|
and $biblio->subscriptions->count == 0
|
|
and $biblio->items->count == 0 )
|
|
{
|
|
|
|
my $error = DelBiblio( $biblio->id );
|
|
$self->add_message(
|
|
{
|
|
message => 'error_delbiblio',
|
|
payload => { biblio => $biblio, reason => $error }
|
|
}
|
|
) if $error;
|
|
$self->biblionumber(undef) unless $error; # constraint cleared biblionumber in db already
|
|
} else {
|
|
|
|
my $message;
|
|
|
|
if ( $biblio->uncancelled_orders->search( { ordernumber => { '!=' => $self->ordernumber } } )->count > 0 ) {
|
|
$message = 'error_delbiblio_uncancelled_orders';
|
|
} elsif ( $biblio->subscriptions->count > 0 ) {
|
|
$message = 'error_delbiblio_subscriptions';
|
|
} else { # $biblio->items->count > 0
|
|
$message = 'error_delbiblio_items';
|
|
}
|
|
|
|
$self->add_message(
|
|
{
|
|
message => $message,
|
|
payload => { biblio => $biblio }
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
# Update order status; do not overwrite older cancellation date
|
|
$self->datecancellationprinted(dt_from_string) unless $self->datecancellationprinted;
|
|
$self->set(
|
|
{
|
|
cancellationreason => $reason,
|
|
orderstatus => 'cancelled',
|
|
}
|
|
)->store;
|
|
|
|
return $self;
|
|
}
|
|
|
|
=head3 add_item
|
|
|
|
$order->add_item( $itemnumber );
|
|
|
|
Link an item to this order.
|
|
|
|
=cut
|
|
|
|
sub add_item {
|
|
my ( $self, $itemnumber ) = @_;
|
|
|
|
my $schema = Koha::Database->new->schema;
|
|
my $rs = $schema->resultset('AqordersItem');
|
|
$rs->create( { ordernumber => $self->ordernumber, itemnumber => $itemnumber } );
|
|
}
|
|
|
|
=head3 basket
|
|
|
|
my $basket = $order->basket;
|
|
|
|
Returns the I<Koha::Acquisition::Basket> object for the basket associated
|
|
to the order.
|
|
|
|
=cut
|
|
|
|
sub basket {
|
|
my ($self) = @_;
|
|
my $basket_rs = $self->_result->basket;
|
|
return Koha::Acquisition::Basket->_new_from_dbic($basket_rs);
|
|
}
|
|
|
|
=head3 fund
|
|
|
|
my $fund = $order->fund;
|
|
|
|
Returns the I<Koha::Acquisition::Fund> object for the fund (aqbudgets)
|
|
associated to the order.
|
|
|
|
=cut
|
|
|
|
sub fund {
|
|
my ($self) = @_;
|
|
my $fund_rs = $self->_result->fund;
|
|
return Koha::Acquisition::Fund->_new_from_dbic($fund_rs);
|
|
}
|
|
|
|
=head3 invoice
|
|
|
|
my $invoice = $order->invoice;
|
|
|
|
Returns the I<Koha::Acquisition::Invoice> object for the invoice associated
|
|
to the order.
|
|
|
|
It returns B<undef> if no linked invoice is found.
|
|
|
|
=cut
|
|
|
|
sub invoice {
|
|
my ($self) = @_;
|
|
my $invoice_rs = $self->_result->invoice;
|
|
return unless $invoice_rs;
|
|
return Koha::Acquisition::Invoice->_new_from_dbic($invoice_rs);
|
|
}
|
|
|
|
=head3 subscription
|
|
|
|
my $subscription = $order->subscription
|
|
|
|
Returns the I<Koha::Subscription> object for the subscription associated
|
|
to the order.
|
|
|
|
It returns B<undef> if no linked subscription is found.
|
|
|
|
=cut
|
|
|
|
sub subscription {
|
|
my ($self) = @_;
|
|
my $subscription_rs = $self->_result->subscription;
|
|
return unless $subscription_rs;
|
|
return Koha::Subscription->_new_from_dbic($subscription_rs);
|
|
}
|
|
|
|
=head3 current_item_level_holds
|
|
|
|
my $holds = $order->current_item_level_holds;
|
|
|
|
Returns the current item-level holds associated to the order. It returns a I<Koha::Holds>
|
|
resultset.
|
|
|
|
=cut
|
|
|
|
sub current_item_level_holds {
|
|
my ($self) = @_;
|
|
|
|
my $items_rs = $self->_result->aqorders_items;
|
|
my @item_numbers = $items_rs->get_column('itemnumber')->all;
|
|
my $biblio = $self->biblio;
|
|
|
|
unless ( $biblio and @item_numbers ) {
|
|
return Koha::Holds->new->empty;
|
|
}
|
|
|
|
return $biblio->current_holds->search( { itemnumber => { -in => \@item_numbers } } );
|
|
}
|
|
|
|
=head3 items
|
|
|
|
my $items = $order->items
|
|
|
|
Returns the items associated to the order.
|
|
|
|
=cut
|
|
|
|
sub items {
|
|
my ($self) = @_;
|
|
|
|
# aqorders_items is not a join table
|
|
# There is no FK on items (may have been deleted)
|
|
my $items_rs = $self->_result->aqorders_items;
|
|
my @itemnumbers = $items_rs->get_column('itemnumber')->all;
|
|
return Koha::Items->search( { itemnumber => \@itemnumbers } );
|
|
}
|
|
|
|
=head3 biblio
|
|
|
|
my $biblio = $order->biblio
|
|
|
|
Returns the bibliographic record associated to the order
|
|
|
|
=cut
|
|
|
|
sub biblio {
|
|
my ($self) = @_;
|
|
my $biblio_rs = $self->_result->biblio;
|
|
return unless $biblio_rs;
|
|
return Koha::Biblio->_new_from_dbic($biblio_rs);
|
|
}
|
|
|
|
=head3 claims
|
|
|
|
my $claims = $order->claims
|
|
|
|
Return the claims history for this order
|
|
|
|
=cut
|
|
|
|
sub claims {
|
|
my ($self) = @_;
|
|
my $claims_rs = $self->_result->aqorders_claims;
|
|
return Koha::Acquisition::Order::Claims->_new_from_dbic($claims_rs);
|
|
}
|
|
|
|
=head3 claim
|
|
|
|
my $claim = $order->claim
|
|
|
|
Do claim for this order
|
|
|
|
=cut
|
|
|
|
sub claim {
|
|
my ($self) = @_;
|
|
my $claim_rs = $self->_result->create_related( 'aqorders_claims', {} );
|
|
return Koha::Acquisition::Order::Claim->_new_from_dbic($claim_rs);
|
|
}
|
|
|
|
=head3 claims_count
|
|
|
|
my $nb_of_claims = $order->claims_count;
|
|
|
|
This is the equivalent of $order->claims->count. Keeping it for retrocompatibilty.
|
|
|
|
=cut
|
|
|
|
sub claims_count {
|
|
my ($self) = @_;
|
|
return $self->claims->count;
|
|
}
|
|
|
|
=head3 claimed_date
|
|
|
|
my $last_claim_date = $order->claimed_date;
|
|
|
|
This is the equivalent of $order->claims->last->claimed_on. Keeping it for retrocompatibilty.
|
|
|
|
=cut
|
|
|
|
sub claimed_date {
|
|
my ($self) = @_;
|
|
my $last_claim = $self->claims->last;
|
|
return unless $last_claim;
|
|
return $last_claim->claimed_on;
|
|
}
|
|
|
|
=head3 creator
|
|
|
|
my $creator = $order->creator;
|
|
|
|
Retrieves patron that created this order.
|
|
|
|
=cut
|
|
|
|
sub creator {
|
|
my ($self) = @_;
|
|
my $creator_rs = $self->_result->creator;
|
|
return unless $creator_rs;
|
|
return Koha::Patron->_new_from_dbic($creator_rs);
|
|
}
|
|
|
|
=head3 duplicate_to
|
|
|
|
my $duplicated_order = $order->duplicate_to($basket, [$default_values]);
|
|
|
|
Duplicate an existing order and attach it to a basket. $default_values can be specified as a hashref
|
|
that contain default values for the different order's attributes.
|
|
Items will be duplicated as well but barcodes will be set to null.
|
|
|
|
=cut
|
|
|
|
sub duplicate_to {
|
|
my ( $self, $basket, $default_values ) = @_;
|
|
my $new_order;
|
|
$default_values //= {};
|
|
Koha::Database->schema->txn_do(
|
|
sub {
|
|
my $order_info = $self->unblessed;
|
|
undef $order_info->{ordernumber};
|
|
for my $field (
|
|
qw(
|
|
ordernumber
|
|
datereceived
|
|
invoiceid
|
|
datecancellationprinted
|
|
cancellationreason
|
|
parent_ordernumber
|
|
)
|
|
)
|
|
{
|
|
undef $order_info->{$field};
|
|
}
|
|
$order_info->{entrydate} = dt_from_string;
|
|
$order_info->{orderstatus} = 'new';
|
|
$order_info->{quantityreceived} = 0;
|
|
while ( my ( $field, $value ) = each %$default_values ) {
|
|
$order_info->{$field} = $value;
|
|
}
|
|
|
|
my $userenv = C4::Context->userenv;
|
|
$order_info->{created_by} = $userenv->{number};
|
|
$order_info->{basketno} = $basket->basketno;
|
|
|
|
$new_order = Koha::Acquisition::Order->new($order_info)->store;
|
|
|
|
if ( !$self->subscriptionid && $self->basket->effective_create_items eq 'ordering' )
|
|
{ # Do copy items if not a subscription order AND if items are created on ordering
|
|
my $items = $self->items;
|
|
while ( my ($item) = $items->next ) {
|
|
my $item_info = $item->unblessed;
|
|
undef $item_info->{itemnumber};
|
|
undef $item_info->{barcode};
|
|
my $new_item = Koha::Item->new($item_info)->store;
|
|
$new_order->add_item( $new_item->itemnumber );
|
|
}
|
|
}
|
|
}
|
|
);
|
|
return $new_order;
|
|
}
|
|
|
|
=head3 populate_with_prices_for_ordering
|
|
|
|
Sets calculated values for an order - all values are stored with full precision
|
|
regardless of rounding preference except for tax value which is calculated on
|
|
rounded values if requested
|
|
|
|
$order->populate_with_prices_for_ordering()
|
|
|
|
The values set are:
|
|
rrp_tax_included
|
|
rrp_tax_excluded
|
|
ecost_tax_included
|
|
ecost_tax_excluded
|
|
tax_value_on_ordering
|
|
|
|
=cut
|
|
|
|
sub populate_with_prices_for_ordering {
|
|
my ($self) = @_;
|
|
|
|
my $bookseller = $self->basket->bookseller;
|
|
return unless $bookseller;
|
|
|
|
my $discount = $self->discount || 0;
|
|
$discount /= 100 if $discount > 1;
|
|
my $unitprice = $self->unitprice // 0;
|
|
|
|
if ( $bookseller->listincgst ) {
|
|
|
|
# The user entered the prices tax included
|
|
$self->unitprice($unitprice);
|
|
$self->unitprice_tax_included($unitprice);
|
|
$self->rrp_tax_included( $self->rrp );
|
|
|
|
# price tax excluded = price tax included / ( 1 + tax rate )
|
|
$self->unitprice_tax_excluded( $self->unitprice_tax_included / ( 1 + $self->tax_rate_on_ordering ) );
|
|
$self->rrp_tax_excluded( $self->rrp_tax_included / ( 1 + $self->tax_rate_on_ordering ) );
|
|
|
|
# ecost tax included = rrp tax included ( 1 - discount )
|
|
$self->ecost_tax_included( $self->rrp_tax_included * ( 1 - $discount ) );
|
|
|
|
# ecost tax excluded = rrp tax excluded * ( 1 - discount )
|
|
$self->ecost_tax_excluded( $self->rrp_tax_excluded * ( 1 - $discount ) );
|
|
|
|
# tax value = quantity * ecost tax excluded * tax rate
|
|
# we should use the unitprice if included
|
|
my $cost_tax_included =
|
|
$self->unitprice_tax_included == 0 ? $self->ecost_tax_included : $self->unitprice_tax_included;
|
|
my $cost_tax_excluded =
|
|
$self->unitprice_tax_excluded == 0 ? $self->ecost_tax_excluded : $self->unitprice_tax_excluded;
|
|
$self->tax_value_on_ordering(
|
|
(
|
|
C4::Acquisition::get_rounded_price($cost_tax_included) -
|
|
C4::Acquisition::get_rounded_price($cost_tax_excluded)
|
|
) * $self->quantity
|
|
);
|
|
} else {
|
|
|
|
# The user entered the prices tax excluded
|
|
$self->unitprice_tax_excluded($unitprice);
|
|
$self->rrp_tax_excluded( $self->rrp );
|
|
|
|
# price tax included = price tax excluded * ( 1 - tax rate )
|
|
$self->unitprice_tax_included( $self->unitprice_tax_excluded * ( 1 + $self->tax_rate_on_ordering ) );
|
|
$self->rrp_tax_included( $self->rrp_tax_excluded * ( 1 + $self->tax_rate_on_ordering ) );
|
|
|
|
# ecost tax excluded = rrp tax excluded * ( 1 - discount )
|
|
$self->ecost_tax_excluded( $self->rrp_tax_excluded * ( 1 - $discount ) );
|
|
|
|
# ecost tax included = rrp tax excluded * ( 1 + tax rate ) * ( 1 - discount ) = ecost tax excluded * ( 1 + tax rate )
|
|
$self->ecost_tax_included( $self->ecost_tax_excluded * ( 1 + $self->tax_rate_on_ordering ) );
|
|
|
|
# tax value = quantity * ecost tax included * tax rate
|
|
# we should use the unitprice if included
|
|
my $cost_tax_excluded =
|
|
$self->unitprice_tax_excluded == 0 ? $self->ecost_tax_excluded : $self->unitprice_tax_excluded;
|
|
$self->tax_value_on_ordering(
|
|
$self->quantity * C4::Acquisition::get_rounded_price($cost_tax_excluded) * $self->tax_rate_on_ordering );
|
|
}
|
|
}
|
|
|
|
=head3 populate_with_prices_for_receiving
|
|
|
|
Sets calculated values for an order - all values are stored with full precision
|
|
regardless of rounding preference except for tax value which is calculated on
|
|
rounded values if requested
|
|
|
|
$order->populate_with_prices_for_receiving()
|
|
|
|
The values set are:
|
|
unitprice_tax_included
|
|
unitprice_tax_excluded
|
|
tax_value_on_receiving
|
|
|
|
Note: When receiving, if the rounded value of the unitprice matches the rounded
|
|
value of the ecost then then ecost (full precision) is used.
|
|
|
|
=cut
|
|
|
|
sub populate_with_prices_for_receiving {
|
|
my ($self) = @_;
|
|
|
|
my $bookseller = $self->basket->bookseller;
|
|
return unless $bookseller;
|
|
|
|
my $discount = $self->discount || 0;
|
|
$discount /= 100 if $discount > 1;
|
|
|
|
if ( $bookseller->invoiceincgst ) {
|
|
|
|
# Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
|
|
# we need to keep the exact ecost value
|
|
if ( Koha::Number::Price->new( $self->unitprice )->round ==
|
|
Koha::Number::Price->new( $self->ecost_tax_included )->round )
|
|
{
|
|
$self->unitprice( $self->ecost_tax_included );
|
|
}
|
|
|
|
# The user entered the unit price tax included
|
|
$self->unitprice_tax_included( $self->unitprice );
|
|
|
|
# unit price tax excluded = unit price tax included / ( 1 + tax rate )
|
|
$self->unitprice_tax_excluded( $self->unitprice_tax_included / ( 1 + $self->tax_rate_on_receiving ) );
|
|
} else {
|
|
|
|
# Trick for unitprice. If the unit price rounded value is the same as the ecost rounded value
|
|
# we need to keep the exact ecost value
|
|
if ( Koha::Number::Price->new( $self->unitprice )->round ==
|
|
Koha::Number::Price->new( $self->ecost_tax_excluded )->round )
|
|
{
|
|
$self->unitprice( $self->ecost_tax_excluded );
|
|
}
|
|
|
|
# The user entered the unit price tax excluded
|
|
$self->unitprice_tax_excluded( $self->unitprice );
|
|
|
|
# unit price tax included = unit price tax included * ( 1 + tax rate )
|
|
$self->unitprice_tax_included( $self->unitprice_tax_excluded * ( 1 + $self->tax_rate_on_receiving ) );
|
|
}
|
|
|
|
# tax value = quantity * unit price tax excluded * tax rate
|
|
$self->tax_value_on_receiving( $self->quantity *
|
|
C4::Acquisition::get_rounded_price( $self->unitprice_tax_excluded ) * $self->tax_rate_on_receiving );
|
|
}
|
|
|
|
=head3 to_api_mapping
|
|
|
|
This method returns the mapping for representing a Koha::Acquisition::Order object
|
|
on the API.
|
|
|
|
=cut
|
|
|
|
sub to_api_mapping {
|
|
return {
|
|
basketno => 'basket_id',
|
|
biblionumber => 'biblio_id',
|
|
deleted_biblionumber => 'deleted_biblio_id',
|
|
budget_id => 'fund_id',
|
|
budgetdate => undef, # unused
|
|
cancellationreason => 'cancellation_reason',
|
|
claimed_date => 'last_claim_date',
|
|
datecancellationprinted => 'cancellation_date',
|
|
datereceived => 'date_received',
|
|
discount => 'discount_rate',
|
|
entrydate => 'entry_date',
|
|
freight => 'shipping_cost',
|
|
invoiceid => 'invoice_id',
|
|
line_item_id => undef, # EDIFACT related
|
|
listprice => 'list_price',
|
|
order_internalnote => 'internal_note',
|
|
order_vendornote => 'vendor_note',
|
|
ordernumber => 'order_id',
|
|
orderstatus => 'status',
|
|
parent_ordernumber => 'parent_order_id',
|
|
quantityreceived => 'quantity_received',
|
|
replacementprice => 'replacement_price',
|
|
servicing_instruction => undef, # EDIFACT related
|
|
sort1 => 'statistics_1',
|
|
sort1_authcat => 'statistics_1_authcat',
|
|
sort2 => 'statistics_2',
|
|
sort2_authcat => 'statistics_2_authcat',
|
|
subscriptionid => 'subscription_id',
|
|
suppliers_reference_number => undef, # EDIFACT related
|
|
suppliers_reference_qualifier => undef, # EDIFACT related
|
|
suppliers_report => undef, # EDIFACT related
|
|
tax_rate_bak => undef, # unused
|
|
tax_value_bak => undef, # unused
|
|
uncertainprice => 'uncertain_price',
|
|
unitprice => 'unit_price',
|
|
unitprice_tax_excluded => 'unit_price_tax_excluded',
|
|
unitprice_tax_included => 'unit_price_tax_included',
|
|
invoice_unitprice => 'invoice_unit_price',
|
|
};
|
|
}
|
|
|
|
=head2 Internal methods
|
|
|
|
=head3 _type
|
|
|
|
=cut
|
|
|
|
sub _type {
|
|
return 'Aqorder';
|
|
}
|
|
|
|
1;
|