Conflicts: docs/gotcha.txt docs/previousVersion.sql docs/templates.txt lib/WebGUI.pm lib/WebGUI/Asset.pm lib/WebGUI/Asset/Event.pm lib/WebGUI/Asset/File.pm lib/WebGUI/Asset/MapPoint.pm lib/WebGUI/Asset/RichEdit.pm lib/WebGUI/Asset/Sku/Product.pm lib/WebGUI/Asset/Snippet.pm lib/WebGUI/Asset/Story.pm lib/WebGUI/Asset/Template.pm lib/WebGUI/Asset/Template/TemplateToolkit.pm lib/WebGUI/Asset/Wobject/Calendar.pm lib/WebGUI/Asset/Wobject/Carousel.pm lib/WebGUI/Asset/Wobject/Collaboration.pm lib/WebGUI/Asset/Wobject/Dashboard.pm lib/WebGUI/Asset/Wobject/DataForm.pm lib/WebGUI/Asset/Wobject/Folder.pm lib/WebGUI/Asset/Wobject/Map.pm lib/WebGUI/Asset/Wobject/Search.pm lib/WebGUI/Asset/Wobject/Shelf.pm lib/WebGUI/Asset/Wobject/StockData.pm lib/WebGUI/Asset/Wobject/StoryTopic.pm lib/WebGUI/Asset/Wobject/SyndicatedContent.pm lib/WebGUI/Asset/Wobject/Thingy.pm lib/WebGUI/Asset/Wobject/WeatherData.pm lib/WebGUI/AssetClipboard.pm lib/WebGUI/AssetCollateral/DataForm/Entry.pm lib/WebGUI/AssetExportHtml.pm lib/WebGUI/AssetLineage.pm lib/WebGUI/AssetMetaData.pm lib/WebGUI/AssetTrash.pm lib/WebGUI/AssetVersioning.pm lib/WebGUI/Auth.pm lib/WebGUI/Cache/CHI.pm lib/WebGUI/Content/AssetManager.pm lib/WebGUI/Fork/ProgressBar.pm lib/WebGUI/Form/JsonTable.pm lib/WebGUI/Form/TimeField.pm lib/WebGUI/Form/Zipcode.pm lib/WebGUI/Group.pm lib/WebGUI/International.pm lib/WebGUI/Macro/AssetProxy.pm lib/WebGUI/Macro/FileUrl.pm lib/WebGUI/Operation/SSO.pm lib/WebGUI/Operation/User.pm lib/WebGUI/Role/Asset/Subscribable.pm lib/WebGUI/Shop/Cart.pm lib/WebGUI/Shop/Transaction.pm lib/WebGUI/Shop/TransactionItem.pm lib/WebGUI/Test.pm lib/WebGUI/URL/Content.pm lib/WebGUI/URL/Uploads.pm lib/WebGUI/User.pm lib/WebGUI/Workflow/Activity/ExtendCalendarRecurrences.pm lib/WebGUI/Workflow/Activity/SendNewsletters.pm lib/WebGUI/i18n/English/Asset.pm lib/WebGUI/i18n/English/WebGUI.pm sbin/installClass.pl sbin/rebuildLineage.pl sbin/search.pl sbin/testEnvironment.pl t/Asset/Asset.t t/Asset/AssetClipboard.t t/Asset/AssetLineage.t t/Asset/AssetMetaData.t t/Asset/Event.t t/Asset/File.t t/Asset/File/Image.t t/Asset/Post/notification.t t/Asset/Sku.t t/Asset/Story.t t/Asset/Template.t t/Asset/Wobject/Collaboration/templateVariables.t t/Asset/Wobject/Collaboration/unarchiveAll.t t/Asset/Wobject/Shelf.t t/Auth.t t/Macro/EditableToggle.t t/Macro/FilePump.t t/Shop/Cart.t t/Shop/Transaction.t t/Storage.t t/User.t t/Workflow.t
441 lines
12 KiB
Perl
441 lines
12 KiB
Perl
package WebGUI::Shop::TransactionItem;
|
|
|
|
use strict;
|
|
|
|
use Scalar::Util qw/blessed/;
|
|
use Moose;
|
|
use WebGUI::Definition;
|
|
use JSON qw{ to_json };
|
|
|
|
property assetId => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property configuredTitle => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property options => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
default => sub { return {}; },
|
|
traits => ['Hash', 'WebGUI::Definition::Meta::Property::Serialize',],
|
|
isa => 'WebGUI::Type::JSONHash',
|
|
coerce => 1,
|
|
);
|
|
|
|
property quantity => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => 1,
|
|
);
|
|
property price => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => 0,
|
|
);
|
|
property vendorId => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => 'defaultvendor000000000',
|
|
);
|
|
property vendorPayoutAmount => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => 0.00,
|
|
);
|
|
property vendorPayoutStatus => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => 'NotPaid',
|
|
);
|
|
property shippingTrackingNumber => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property orderStatus => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => 'NotShipped',
|
|
);
|
|
property shippingAddressId => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingName => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingOrganization => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingAddress1 => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingAddress2 => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingAddress3 => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingCity => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingState => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingCountry => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingCode => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property shippingPhoneNumber => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property taxRate => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
property taxConfiguration => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
|
|
property lastUpdated => (
|
|
is => 'rw',
|
|
noFormPost => 1,
|
|
default => '',
|
|
);
|
|
|
|
has [ qw/transaction itemId/ ] => (
|
|
is => 'ro',
|
|
required => 1,
|
|
);
|
|
|
|
has item => (
|
|
is => 'rw',
|
|
trigger => \&_mine_item,
|
|
);
|
|
|
|
sub _mine_item {
|
|
my ($self, $item) = @_;
|
|
my $sku = $item->getSku;
|
|
$self->options($sku->getOptions);
|
|
$self->assetId($sku->getId);
|
|
$self->price($sku->getPrice);
|
|
$self->configuredTitle($item->get('configuredTitle'));
|
|
$self->quantity($item->get('quantity'));
|
|
$self->vendorId($sku->getVendorId);
|
|
$self->vendorPayoutAmount(sprintf '%.2f', $sku->getVendorPayout * $item->get('quantity'));
|
|
|
|
my $address = $item->getShippingAddress;
|
|
$self->shippingAddressId($address->getId);
|
|
$self->shippingName(join ' ', $address->firstName, $address->lastName);
|
|
$self->shippingAddress1($address->address1);
|
|
$self->shippingAddress2($address->address2);
|
|
$self->shippingAddress3($address->address3);
|
|
$self->shippingCity($address->city);
|
|
$self->shippingState($address->state);
|
|
$self->shippingCountry($address->country);
|
|
$self->shippingCode($address->code);
|
|
$self->shippingPhoneNumber($address->phoneNumber);
|
|
|
|
# Store tax rate for product
|
|
my $transaction = $self->transaction;
|
|
my $taxDriver = WebGUI::Shop::Tax->getDriver( $transaction->session );
|
|
$self->taxRate($taxDriver->getTaxRate( $sku, $address ));
|
|
$self->taxConfiguration(to_json( $taxDriver->getTransactionTaxData( $sku, $address ) || '{}' ));
|
|
|
|
if (!$sku->isShippingRequired && $transaction->isSuccessful) {
|
|
$self->orderStatus('Shipped');
|
|
}
|
|
}
|
|
|
|
use WebGUI::DateTime;
|
|
use WebGUI::Exception::Shop;
|
|
use WebGUI::Shop::Transaction;
|
|
use WebGUI::Shop::Tax;
|
|
|
|
=head1 NAME
|
|
|
|
Package WebGUI::Shop::TransactionItem
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Each transaction item represents a sku that was purchased or attempted to be purchased.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use WebGUI::Shop::TransactionItem;
|
|
|
|
my $item = WebGUI::Shop::TransactionItem->new($transaction);
|
|
|
|
=head1 METHODS
|
|
|
|
These subroutines are available from this package:
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 new ( transaction, itemId )
|
|
|
|
Constructor. Instanciates a transaction item based upon itemId.
|
|
|
|
=head2 new ( properties )
|
|
|
|
Constructor. Builds a new transaction item object. The properties of the newly created object are not persisted
|
|
to the database. The write method must be called on the object to do that.
|
|
|
|
=head2 new ( transaction, properties )
|
|
|
|
Constructor. Builds a new transaction item object. This form of new is
|
|
deprecated, and only exists for backwards compatibility with the old "create"
|
|
method. The properties of the newly created object are not persisted to
|
|
the database. The write method must be called on the object to do that.
|
|
|
|
=head3 transaction
|
|
|
|
A reference to the current transaction object.
|
|
|
|
=head3 itemId
|
|
|
|
The unique id of the item to instanciate.
|
|
|
|
=head3 properties
|
|
|
|
A hash reference that contains one of the following:
|
|
|
|
=head4 item
|
|
|
|
A reference to a WebGUI::Shop::CartItem. Alternatively you can manually pass in any of the following
|
|
fields that would be created automatically by this object: assetId configuredTitle options shippingAddressId
|
|
shippingName shippingAddress1 shippingAddress2 shippingAddress3 shippingCity shippingState shippingCountry
|
|
shippingCode shippingPhoneNumber quantity price vendorId
|
|
|
|
=head4 shippingTrackingNumber
|
|
|
|
A tracking number that is used by the shipping method for this transaction.
|
|
|
|
=head4 orderStatus
|
|
|
|
The status of this item. The default is 'NotShipped'. Other statuses include: Cancelled, Backordered, Shipped
|
|
|
|
=cut
|
|
|
|
around BUILDARGS => sub {
|
|
my $orig = shift;
|
|
my $class = shift;
|
|
if (ref $_[0] eq 'HASH') {
|
|
my $properties = $_[0];
|
|
my $transaction = $properties->{transaction};
|
|
if (! (blessed $transaction && $transaction->isa("WebGUI::Shop::Transaction"))) {
|
|
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Shop::Transaction", got=>(ref $transaction), error=>"Need a transaction.");
|
|
}
|
|
my ($itemId) = $class->_init($transaction);
|
|
$properties->{itemId} = $itemId;
|
|
$properties->{transactionId} = $transaction->getId;
|
|
return $class->$orig($properties);
|
|
}
|
|
my $transaction = shift;
|
|
if (! (blessed $transaction && $transaction->isa("WebGUI::Shop::Transaction"))) {
|
|
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Shop::Transaction", got=>(ref $transaction), error=>"Need a transaction.");
|
|
}
|
|
my $argument2 = shift;
|
|
if (!defined $argument2) {
|
|
WebGUI::Error::InvalidParam->throw( param=>$argument2, error=>"Need a itemId.");
|
|
}
|
|
if (ref $argument2 eq 'HASH') {
|
|
##Build a new one
|
|
my ($itemId) = $class->_init($transaction);
|
|
my $properties = $argument2;
|
|
$properties->{transaction} = $transaction;
|
|
$properties->{itemId} = $itemId;
|
|
return $class->$orig($properties);
|
|
}
|
|
else {
|
|
##Look up one in the db
|
|
my $item = $transaction->session->db->quickHashRef("select * from transactionItem where itemId=?", [$argument2]);
|
|
if ($item->{transactionId} eq "") {
|
|
WebGUI::Error::ObjectNotFound->throw(error=>"Item not found", id=>$argument2);
|
|
}
|
|
if ($item->{transactionId} ne $transaction->getId) {
|
|
WebGUI::Error::ObjectNotFound->throw(error=>"Item not in this transaction.", id=>$argument2);
|
|
}
|
|
$item->{transaction} = $transaction;
|
|
return $class->$orig($item);
|
|
}
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 _init ( session )
|
|
|
|
Builds a stub of object information in the database, and returns the newly created
|
|
transactionId, and the dateOfPurchase fields so the object can be initialized correctly.
|
|
|
|
=cut
|
|
|
|
sub _init {
|
|
my $class = shift;
|
|
my $transaction = shift;
|
|
my $session = $transaction->session;
|
|
my $itemId = $session->id->generate;
|
|
$session->db->write("insert into transactionItem (itemId, transactionId) values (?, ?)",[$itemId, $transaction->getId]);
|
|
return ($itemId);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 delete ( )
|
|
|
|
Removes this item from the transaction.
|
|
|
|
=cut
|
|
|
|
sub delete {
|
|
my $self = shift;
|
|
$self->transaction->session->db->deleteRow("transactionItem", "itemId", $self->getId);
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getId ()
|
|
|
|
Returns the unique id of this item.
|
|
|
|
=cut
|
|
|
|
sub getId {
|
|
my $self = shift;
|
|
return $self->itemId;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSku ( )
|
|
|
|
Returns an instanciated WebGUI::Asset::Sku object for this item.
|
|
|
|
=cut
|
|
|
|
sub getSku {
|
|
my ($self) = @_;
|
|
my $asset = eval { WebGUI::Asset->newById($self->transaction->session, $self->assetId); };
|
|
if (Exception::Class->caught()) {
|
|
WebGUI::Error::ObjectNotFound->throw(error=>'SKU Asset '.$self->assetId.' could not be instanciated. Perhaps it no longer exists.', id=>$self->assetId);
|
|
return undef;
|
|
}
|
|
$asset->applyOptions($self->options);
|
|
return $asset;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 issueCredit ( )
|
|
|
|
Returns the money from this item to the user in the form of in-store credit. Items marked
|
|
cancelled cannot be refunded.
|
|
|
|
=cut
|
|
|
|
sub issueCredit {
|
|
my $self = shift;
|
|
return if $self->orderStatus eq 'Cancelled';
|
|
return unless $self->transaction->isSuccessful;
|
|
my $credit = WebGUI::Shop::Credit->new($self->transaction->session, $self->transaction->userId);
|
|
$credit->adjust(($self->price * $self->quantity), "Issued credit on sku ".$self->assetId." for transaction item ".$self->getId." on transaction ".$self->transaction->getId);
|
|
if (my $sku = eval {$self->getSku}) {
|
|
$sku->onRefund($self);
|
|
}
|
|
$self->update({orderStatus=>'Cancelled'});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 newByDynamicTransaction ( session, itemId )
|
|
|
|
Constructor, but will dynamically find the approriate transaction and attach it to the item object.
|
|
|
|
=head3 session
|
|
|
|
A reference to the current session.
|
|
|
|
=head3 itemId
|
|
|
|
The unique id for this transaction item.
|
|
|
|
=cut
|
|
|
|
sub newByDynamicTransaction {
|
|
my ($class, $session, $itemId) = @_;
|
|
unless (defined $session && $session->isa("WebGUI::Session")) {
|
|
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session.");
|
|
}
|
|
unless (defined $itemId) {
|
|
WebGUI::Error::InvalidParam->throw(error=>"Need an itemId.");
|
|
}
|
|
my $transactionId = $session->db->quickScalar("select transactionId from transactionItem where itemId=?",[$itemId]);
|
|
my $transaction = WebGUI::Shop::Transaction->new($session, $transactionId);
|
|
return $class->new($transaction, $itemId);
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 transaction ( )
|
|
|
|
Returns a reference to the transaction object.
|
|
|
|
=cut
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 write ( )
|
|
|
|
Stores the object's properties to the database.
|
|
|
|
=cut
|
|
|
|
sub write {
|
|
my ($self) = @_;
|
|
my $transaction = $self->transaction;
|
|
my $session = $transaction->session;
|
|
$self->lastUpdated(WebGUI::DateTime->new($session,time())->toDatabase);
|
|
my %properties = %{ $self->get() };
|
|
$properties{options} = JSON->new->encode($properties{options});
|
|
delete @properties{qw/transaction item/};
|
|
$session->db->setRow("transactionItem", "itemId", \%properties);
|
|
}
|
|
|
|
|
|
1;
|