package webshop::Keeper;
use strict;
use warnings 'all';
use base qw(Contenido::Keeper);
use Data::Dumper;
use Contenido::Globals;
use webshop::Basket;
use webshop::SQL::Basket;
sub add_item {
my $self = shift;
my $object = shift;
my (%options) = @_;
return unless ref $object;
return unless $object->item_id && $object->number;
return unless $object->uid || $object->session;
my %opts;
if ( $object->uid ) {
$opts{uid} = $object->uid;
} elsif ( $object->session ) {
$opts{session} = $object->session;
}
my @items = $keeper->get_documents (
class => 'webshop::Basket',
status => 1,
order_id=> 0,
%opts,
);
my $total = 0;
my $sum = 0;
my $found = 0;
if ( @items ) {
foreach my $item ( @items ) {
if ( $object->item_id == $item->item_id && $object->color_id == $item->color_id &&
((!$object->size_id && !$object->size) || ($object->size_id && $object->size_id == $item->size_id) || ($object->size && $object->size eq $item->size)) ) {
$item->number( $item->number + $object->number );
$item->price( $object->price );
$item->store;
$found = 1;
}
$total += $item->number;
$sum += $item->number * $item->price;
}
}
unless ( $found ) {
$total += $object->number;
$sum += $object->number * $object->price;
$object->order_id(0);
$object->store;
}
my @plugins = split (/[\ |\t]+/, $state->{plugins});
if ( grep { $_ eq 'session' } @plugins && ref $session ) {
$session->set ( basket_total => $total, basket_sum => $sum );
}
return ($total, $sum);
}
sub add_wishlist {
my $self = shift;
my $object = shift;
my (%options) = @_;
return unless ref $object;
return unless $object->item_id && $object->number;
return unless $object->uid || $object->session;
my %opts;
if ( $object->uid ) {
$opts{uid} = $object->uid;
} elsif ( $object->session ) {
$opts{session} = $object->session;
}
my @items = $keeper->get_documents (
class => 'webshop::Basket',
status => 0,
order_id=> 0,
%opts,
);
my $total = 0;
my $sum = 0;
my $found = 0;
if ( @items ) {
foreach my $item ( @items ) {
if ( $object->item_id == $item->item_id && $object->color_id == $item->color_id &&
((!$object->size_id && !$object->size) || ($object->size_id && $object->size_id == $item->size_id) || ($object->size && $object->size eq $item->size)) ) {
$item->number($item->number + $object->number);
$item->store;
$found = 1;
}
$total += $item->number;
$sum += $item->number * $item->price;
}
}
unless ( $found ) {
$total += $object->number;
$sum += $object->number * $object->price;
$object->order_id(0);
$object->store;
}
return ($total, $sum);
}
### Метод приведения корзины для пользователя в момент логина
#############################################################
sub merge_basket {
my $self = shift;
my (%opts) = @_;
warn "Merge begin: ".Dumper(\%opts)."\n" if $DEBUG;
return unless $opts{uid} && $opts{session};
my @items = $keeper->get_documents (
class => 'webshop::Basket',
status => [1,0],
order_id=> 0,
session => $opts{session},
);
foreach my $item ( @items ) {
$item->session(undef);
$item->uid( $opts{uid} );
$item->store;
}
@items = $keeper->get_documents (
class => 'webshop::Basket',
status => 1,
order_id=> 0,
uid => $opts{uid},
);
my $total = 0;
my $sum = 0;
foreach my $item ( @items ) {
$total += $item->number;
$sum += $item->number * $item->price;
}
my @plugins = split (/[\ |\t]+/, $state->{plugins});
if ( grep { $_ eq 'session' } @plugins && ref $session ) {
$session->set ( basket_total => $total, basket_sum => $sum );
}
warn "Merge end\n" if $DEBUG;
return ($total, $sum);
}
sub get_basket {
my $self = shift;
my (%opts) = @_;
return unless $opts{uid} || $opts{session} || $opts{order_id};
my $with_products = delete $opts{with_products} || 0;
my $uid = delete $opts{uid};
my $session_id = delete $opts{session};
unless ( exists $opts{order_id} && $opts{order_id} ) {
$opts{order_id} = 0;
if ( $uid ) {
$opts{uid} = $uid;
} elsif ( $session_id ) {
$opts{session} = $session_id;
}
}
$opts{status} = 1 unless exists $opts{status} && defined $opts{status};
my @basket = $keeper->get_documents (
class => 'webshop::Basket',
%opts,
);
my $total = 0;
my $sum = 0;
my $items;
if ( $with_products ) {
my %ids = map { $_->item_id => 1 } @basket;
my @ids = keys %ids;
$items = @ids ? $keeper->get_documents (
id => \@ids,
class => $state->{webshop}->{item_document_class},
status => 'positive',
return_mode => 'hash_ref',
) : {};
}
foreach my $bi ( @basket ) {
if ( $bi->status == 1 ) {
$total += $bi->number;
$sum += $bi->number * ($bi->price || 0);
}
if ( ref $items eq 'HASH' && exists $items->{$bi->item_id} ) {
$bi->{item} = $items->{$bi->item_id};
}
}
return \@basket;
}
sub basket_count {
my $self = shift;
my $basket = shift;
return (0,0) unless ref $basket eq 'ARRAY' && @$basket;
my $total = 0;
my $sum = 0;
foreach my $item ( @$basket ) {
if ( $item->status == 1 ) {
$total += $item->number;
$sum += $item->number * $item->price;
}
}
return ($total, $sum);
}
sub wishlist_count {
my $self = shift;
my $basket = shift;
return (0,0) unless ref $basket eq 'ARRAY' && @$basket;
my $total = 0;
my $sum = 0;
foreach my $item ( @$basket ) {
if ( $item->status == 0 ) {
$total += $item->number;
$sum += $item->number * $item->price;
}
}
return ($total, $sum);
}
sub clear_basket {
my $self = shift;
my (%opts) = @_;
return unless exists $opts{uid} || exists $opts{session};
my $table_name = webshop::SQL::Basket->db_table;
my $request = "delete from $table_name where order_id = 0 AND status = 1 AND";
my $dbh = $keeper->SQL;
my @vals;
if ( exists $opts{uid} && $opts{uid} ) {
$request .= " uid in (?)";
push @vals, $opts{uid};
} elsif ( exists $opts{session} ) {
$request .= " session in (?)";
push @vals, $opts{session};
}
warn "CLEAR: [$request]. VALS: [".join(',',@vals)."]\n" if $DEBUG;
my $statement = $dbh->prepare ($request);
$statement->execute( @vals ) || $log->error("DBI execute error on $request\n"."\ncalled with opts:\n".Data::Dumper::Dumper(\%opts));;
$statement->finish;
my @plugins = split (/[\ |\t]+/, $state->{plugins});
if ( grep { $_ eq 'session' } @plugins && ref $session ) {
$session->set ( basket_total => 0, basket_sum => 0 );
}
}
sub clear_wishlist {
my $self = shift;
my (%opts) = @_;
return unless exists $opts{uid} || exists $opts{session};
my $table_name = webshop::SQL::Basket->db_table;
my $request = "delete from $table_name where order_id = 0 AND status = 0 AND";
my $dbh = $keeper->SQL;
my @vals;
if ( exists $opts{uid} ) {
$request .= " uid in (?)";
push @vals, $opts{uid};
} elsif ( exists $opts{session} ) {
$request .= " session in (?)";
push @vals, $opts{session};
}
my $statement = $dbh->prepare ($request);
$statement->execute( @vals ) || $log->error("DBI execute error on $request\n"."\ncalled with opts:\n".Data::Dumper::Dumper(\%opts));;
$statement->finish;
}
### Метод пересчета корзины
# Принимает на вход параметры:
# session => session_id пользователя
# uid => UID пользователя
# delete => массив или отдельный item_id
# renumber => ссылка на хеш вида item => number
#############################################################
sub recount {
my $self = shift;
my (%opts) = @_;
warn "Recount Started!!!\n" if $DEBUG;
return unless exists $opts{uid} || exists $opts{session} || exists $opts{order_id};
my $basket = $self->get_basket ( %opts );
return unless ref $basket eq 'ARRAY' && @$basket;
warn Dumper(\%opts) if $DEBUG;
my $total = 0;
my $sum = 0;
my @new_basket;
my $session_no_store = delete $opts{session_no_store};
foreach my $item ( @$basket ) {
my $delete = 0;
if ( exists $opts{renumber} && ref $opts{renumber} eq 'HASH' && exists $opts{renumber}{$item->id} && int($opts{renumber}{$item->id}) == 0 ) {
$delete = 1;
} elsif ( exists $opts{delete} && ref $opts{delete} eq 'ARRAY' ) {
$delete = 1 if grep { $_ == $item->id } @{ $opts{delete} };
} elsif ( exists $opts{delete} && $opts{delete} ) {
$delete = 1 if $item->id == $opts{delete};
}
if ( $delete ) {
warn "Item ID=".$item->id." DELETE\n" if $DEBUG;
$item->delete();
next;
} else {
my $store = 0;
if ( exists $opts{renumber} && ref $opts{renumber} eq 'HASH' && exists $opts{renumber}{$item->id} && $opts{renumber}{$item->id} != $item->number ) {
$item->number( $opts{renumber}{$item->id} );
$store = 1;
}
if ( exists $opts{price} && ref $opts{price} eq 'HASH' && exists $opts{price}{$item->id} && $opts{price}{$item->id} != $item->price ) {
$item->price( $opts{price}{$item->id} );
$store = 1;
}
$item->store if $store;
$total += $item->number;
$sum += $item->number * $item->price;
push @new_basket, $item;
}
}
my @plugins = split (/[\ |\t]+/, $state->{plugins});
if ( !$session_no_store && grep { $_ eq 'session' } @plugins && ref $session ) {
$session->set ( basket_total => $total, basket_sum => $sum );
}
return ($total, $sum, \@new_basket);
}
sub get_orders {
my $self = shift;
my (%opts) = @_;
my $list = delete $opts{list};
my $count = delete $opts{count};
if ( $count ) {
delete $opts{order_by};
my $item_count = $keeper->get_documents (
class => 'webshop::Order',
count => 1,
%opts,
);
return $item_count;
} else {
$opts{order_by} ||= 'status';
my @items = $keeper->get_documents (
class => 'webshop::Order',
%opts,
);
if ( exists $opts{id} && defined $opts{id} && !ref $opts{id} ) {
if ( $list ) {
$items[0]->{list} = $self->get_order_list( order_id => $opts{id} );
}
return $items[0];
} else {
if ( $list ) {
map { $_->{list} = $self->get_order_list( order_id => $_->id ) } @items;
}
return \@items;
}
}
}
sub get_order_list {
my $self = shift;
my (%opts) = @_;
return unless $opts{order_id};
$opts{status} = 1;
my @items = $keeper->get_documents (
class => 'webshop::Basket',
%opts,
);
my $total = 0;
my $sum = 0;
foreach my $item ( @items ) {
my $Item = $item->class->new( $keeper, $item->id );
$item->{item} = $Item;
if ( $item->status == 1 ) {
$total += $item->number;
$sum += $item->number * $item->price;
}
}
return \@items;
}
### Метод приведения купонов для пользователя в момент логина
#############################################################
sub merge_coupons {
my $self = shift;
my (%opts) = @_;
warn "Merge (coupons) begin: ".Dumper(\%opts)."\n" if $DEBUG;
return unless $opts{uid} && $opts{session};
my @items = $keeper->get_links (
class => 'webshop::OrderCouponLink',
session => $opts{session},
source_id => 0,
);
my %merge_to = $keeper->get_links (
class => 'webshop::OrderCouponLink',
uid => $opts{uid},
source_id => 0,
return_mode => 'hash',
hash_by => 'dest_id',
);
foreach my $item ( @items ) {
if ( exists $merge_to{$item->dest_id} ) {
$item->delete;
} else {
$item->session( undef );
$item->uid( $opts{uid} );
$item->store;
}
}
}
sub check_discount {
my $self = shift;
my (%opts) = @_;
warn "Check discount begin:\n" if $DEBUG;
my %dopts;
if ( exists $opts{uid} && $opts{uid} ) {
$dopts{uid} = [0,1];
} else {
$dopts{uid} = 0;
}
my $basket = exists $opts{basket} ? $opts{basket} : $self->get_basket( %opts, with_products => 1 );
return 0 unless ref $basket eq 'ARRAY' && @$basket;
my @basket = grep { exists $_->{item} && $_->{item} } @$basket;
return 0 unless @basket;
my $now = Contenido::DateTime->new;
my @discounts = $keeper->get_documents(
class => 'webshop::Discount',
status => 1,
interval=> [$now, $now],
%dopts,
);
return 0 unless @discounts;
my @summoned = sort { $b->min_sum <=> $a->min_sum } grep { $_->min_sum && $_->discount && $_->min_sum =~ /^\d+$/ } @discounts;
my ($total, $sum) = $self->basket_count( \@basket );
return 0 unless $sum;
my $result = 0;
foreach my $discount ( @summoned ) {
if ( $sum > $discount->min_sum ) {
my $res = $discount->get_discount( basket => \@basket );
$result = $res if $res > $result;
}
}
$result = 0 if $result >= $sum;
return $result;
}
sub check_coupons {
my $self = shift;
my (%opts) = @_;
warn "Check coupons begin:\n" if $DEBUG;
my %dopts;
if ( exists $opts{uid} && $opts{uid} ) {
$dopts{luid} = $opts{uid};
} else {
$dopts{lsession} = $opts{session};
}
my $basket = exists $opts{basket} ? $opts{basket} : $self->get_basket( %opts, with_products => 1 );
return (0, []) unless ref $basket eq 'ARRAY' && @$basket;
my @basket = grep { exists $_->{item} && $_->{item} } @$basket;
return (0, []) unless @basket;
my $now = Contenido::DateTime->new;
my @coupons = exists $opts{coupons} && ref $opts{coupons} eq 'ARRAY' ? @{$opts{coupons}} : $keeper->get_documents(
class => 'webshop::Coupon',
lclass => 'webshop::OrderCouponLink',
lsource => 0,
status => 1,
interval=> [$now->ymd, $now->ymd],
%dopts,
);
return (0, []) unless @coupons;
my @summoned = grep { $_->discount } @coupons;
warn "We count on ".scalar(@summoned)." coupons\n" if $DEBUG;
my ($total, $sum) = $self->basket_count( \@basket );
return (0, \@summoned) unless $sum;
my $result = 0;
foreach my $coupon ( @summoned ) {
my $res = $coupon->get_discount( basket => \@basket );
$coupon->{result} = $res;
}
@summoned = sort { $b->{result} <=> $a->{result} } @summoned;
foreach my $coupon ( @summoned ) {
if ( ($coupon->{result} > 0) && ($sum - $coupon->{result} > 0) ) {
$result += $coupon->{result};
$sum -= $coupon->{result};
$coupon->{afflict_order} = 1;
} else {
$coupon->{afflict_order} = 0;
}
}
return ($result, \@summoned);
}
sub price_format {
my $self = shift;
my $price = shift;
$price = reverse $price;
$price =~ s/(\d{3})/$1\ /g;
$price = reverse $price;
return $price;
}
1;