Committer: ailyin
LJSUP-10483 (Selfpromo delivery mechanics is broken)U trunk/cgi-bin/LJ/Pay/Payment/PayItem/SelfPromo.pm U trunk/cgi-bin/LJ/Pay/SelfPromo.pm
Modified: trunk/cgi-bin/LJ/Pay/Payment/PayItem/SelfPromo.pm =================================================================== --- trunk/cgi-bin/LJ/Pay/Payment/PayItem/SelfPromo.pm 2012-01-23 12:05:56 UTC (rev 11340) +++ trunk/cgi-bin/LJ/Pay/Payment/PayItem/SelfPromo.pm 2012-01-23 15:03:53 UTC (rev 11341) @@ -70,10 +70,17 @@ sub _deliver_item { my ( $self, $payment, $buyer_u, $rcpt_u, $note_rec_change ) = @_; + LJ::Pay::SelfPromo->debug_msg("delivery of a selfpromo item requested"); + LJ::Pay::SelfPromo->debug_msg( "piid=" . $self->get_piid ); + # if we cannot get a lock straight away, let this be delivered later; # resolves race condition with ljmaint.pl and webs trying to deliver # the same item simultaneously - return if LJ::Pay::SelfPromo->lock_taken_elsewhere; + if ( LJ::Pay::SelfPromo->lock_taken_elsewhere ) { + LJ::Pay::SelfPromo->debug_msg( + "actually, another process got the lock, quitting"); + return; + } # this should be temporary until we l10n the shop my $lang = ($rcpt_u && $rcpt_u->prop('browselang')) ? $rcpt_u->prop('browselang') : $LJ::DEFAULT_LANG; @@ -82,11 +89,16 @@ return LJ::Lang::get_text( $lang, $code, undef, $params ); }; + LJ::Pay::SelfPromo->debug_msg("acquiring the lock"); my $lock = LJ::Pay::SelfPromo->lock; + LJ::Pay::SelfPromo->debug_msg("got the lock"); + LJ::Pay::SelfPromo->debug_msg("checking the current entry"); LJ::Pay::SelfPromo->check_current_entry; + LJ::Pay::SelfPromo->debug_msg("current entry checked"); my $type = $self->get_prop('selfpromo_type'); + LJ::Pay::SelfPromo->debug_msg("item type: $type"); # if there's an entry being promoted, deactivate it, and # then handle any refund if need be @@ -95,6 +107,9 @@ # also only cancel the current promotion my $entry_promoted; if ( $entry_promoted = LJ::Pay::SelfPromo->current_entry ) { + LJ::Pay::SelfPromo->debug_msg( + "cancelling the current entry" . $entry_promoted->url ); + LJ::Pay::SelfPromo->deactivate_entry( 'entry' => $entry_promoted, 'reason' => 'buyout', @@ -102,13 +117,22 @@ ); if ( my $refund_userid = $self->get_prop('selfpromo_refund_userid') ) { + LJ::Pay::SelfPromo->debug_msg( + "issuing a refund to userid=$refund_userid"); + my $promoid = $self->get_prop('selfpromo_refund_promoid'); - my $refund_to = LJ::load_userid($refund_userid); + LJ::Pay::SelfPromo->debug_msg("refund promoid=$promoid"); + my $refund_to = LJ::load_userid($refund_userid); + LJ::Pay::SelfPromo->debug_msg( + "refund goes to user=" . $refund_to->username ); + my $promo = LJ::Pay::SelfPromo->current_entry_info($promoid); my $refund = $self->get_prop('selfpromo_refund'); if ($refund) { + LJ::Pay::SelfPromo->debug_msg("crediting them"); + # credit them: LJ::Pay::Wallet->try_add( $refund_to, $refund ); LJ::Pay::Wallet::Log->log( @@ -120,6 +144,8 @@ 'status' => LJ::Pay::Wallet::Log::STATUS_FINISHED, 'time_end' => time, ); + + LJ::Pay::SelfPromo->debug_msg("successfully credited"); } my $entry_url = $promo->entry_url; @@ -130,6 +156,9 @@ 'poster_cancel' => 'poster', }; + LJ::Pay::SelfPromo->debug_msg( + "emailing them that someone bought the place out"); + # email them: LJ::Pay::SelfPromo->send_notification( $refund_to, 'deactivate', @@ -151,6 +180,8 @@ 'notify_poster' => 1, ); } + + LJ::Pay::SelfPromo->debug_msg("refund successful"); } } @@ -161,6 +192,10 @@ my $remainder_to = LJ::load_userid($remainder_to_userid); if ($remainder_to) { + LJ::Pay::SelfPromo->debug_msg( + "sending the remainder of tokens to " . + $remainder_to->username ); + LJ::Pay::Wallet->try_add( $remainder_to, $remainder ); LJ::Pay::Wallet::Log->log( 'userid' => $remainder_to_userid, @@ -184,11 +219,17 @@ my $entry = $self->get_entry; my $poster = $entry->poster; + LJ::Pay::SelfPromo->debug_msg( + "setting the new active entry: " . $entry->url ); + my $cost = $self->get_amt * LJ::Pay::Wallet::EXCHANGE_RATE(); LJ::Pay::SelfPromo->activate_entry( $entry, $cost, $rcpt_u ); + LJ::Pay::SelfPromo->debug_msg("entry activated successfully"); + $email_subject = $ml->('selfpromo.notification.activate.subject'); + LJ::Pay::SelfPromo->debug_msg("generating the emails"); # Need to send second email if entry poster and recipient are different unless ( LJ::u_equals($poster, $rcpt_u) ) { $email_body = $ml->( @@ -231,6 +272,8 @@ ); } + LJ::Pay::SelfPromo->debug_msg("delivery successful"); + return ( 1, $email_subject, $email_body ); } Modified: trunk/cgi-bin/LJ/Pay/SelfPromo.pm =================================================================== --- trunk/cgi-bin/LJ/Pay/SelfPromo.pm 2012-01-23 12:05:56 UTC (rev 11340) +++ trunk/cgi-bin/LJ/Pay/SelfPromo.pm 2012-01-23 15:03:53 UTC (rev 11341) @@ -5,6 +5,9 @@ use LJ::Pay::Wallet; use LJ::Pay::Wallet::Error qw(:codes); use LJ::Pay::SelfPromo::History; + +use Sys::Hostname qw(); + use Exporter; our @ISA = qw(Exporter); @@ -116,32 +119,57 @@ sub buyout { my ( $class, $entry, $promoter, $price ) = @_; + LJ::Pay::SelfPromo->debug_msg( + "buyout requested, " . + "entry => " . $entry->url . ", " . + "promoter => " . $promoter->username . ", " . + "price => $price" + ); + my $lock = $class->lock; + LJ::Pay::SelfPromo->debug_msg("lock acquired successfully"); + ## check entry do { my $reason; + LJ::Pay::SelfPromo->debug_msg("checking if the entry is eligible..."); + unless ( $class->is_entry_eligible( $entry, $promoter, \$reason ) ) { + LJ::Pay::SelfPromo->debug_msg("no it's not: $reason"); $class->raise_error( ERROR_ENTRY_INELIGIBLE, $reason ); } + + LJ::Pay::SelfPromo->debug_msg("yes it is"); }; ## check price do { + LJ::Pay::SelfPromo->debug_msg("checking the price"); + my $price_additional = $price - $LJ::SELF_PROMO_CONF->{'min_cost'}; if ( $price_additional % $LJ::SELF_PROMO_CONF->{'step'} ) { + LJ::Pay::SelfPromo->debug_msg("price is invalid: $price"); $class->raise_error(ERROR_INVALID_PRICE); } my $min_price = $class->buyout_cost; unless ( $price >= $min_price ) { + LJ::Pay::SelfPromo->debug_msg( + "not enough money offered, need at least $min_price"); + $class->raise_error( ERROR_PRICE_INSUFFICIENT, $min_price ); } - my $wallet_balance = LJ::Pay::Wallet->get_user_balance($promoter); + my $wallet_balance = int LJ::Pay::Wallet->get_user_balance($promoter); unless ( $wallet_balance >= $price ) { + LJ::Pay::SelfPromo->debug_msg( + "promoter doesn't actually have that much " . + "(has $wallet_balance, tried to buy out for $price)" + ); + $class->raise_error( ERROR_WALLET_INSUFFICIENT_FUNDS, - int $wallet_balance ); + $wallet_balance ); } }; @@ -150,6 +178,8 @@ my $cart; do { + LJ::Pay::SelfPromo->debug_msg("creating the cart"); + # calculate how much money goes where for this item: # a part of it goes to the system, a part of it goes to the # user who purchased the selfpromo that was running before the @@ -186,8 +216,13 @@ } ); + LJ::Pay::SelfPromo->debug_msg("cart created, setting the method"); + $cart->set_method( LJ::Pay::Method::Wallet->code ); + + LJ::Pay::SelfPromo->debug_msg("paying for the cart"); LJ::Pay::Wallet->pay_for_cart( $cart->get_payid ); + LJ::Pay::SelfPromo->debug_msg("paid successfully"); }; # deliver the cart synchronously, so that changes are applied @@ -197,17 +232,34 @@ # this part isn't supposed to throw any exceptions because # all the checks have been done before do { + LJ::Pay::SelfPromo->debug_msg("delivering the cart/items"); + LJ::Pay::SelfPromo->debug_msg( "payid=" . $cart->get_payid ); + my ($item) = $cart->get_items; + LJ::Pay::SelfPromo->debug_msg( "piid=" . $item->get_piid ); + $cart->update( 'used' => 'Y' ); $item->update( 'status' => 'pend' ); + LJ::Pay::SelfPromo->debug_msg( + "cart and item updated to be ready for delivery"); + + local $SIG{'__WARN__'} = sub { + my @messages = @_; + LJ::Pay::SelfPromo->debug_msg( "delivery warning: ", @messages ); + warn @messages; + }; + my $deliver_res = $item->deliver( $cart, time, sub { } ); unless ($deliver_res) { + LJ::Pay::SelfPromo->debug_msg("delivery failed"); die "delivering item failed, see error log for details"; } }; + LJ::Pay::SelfPromo->debug_msg("all done"); + LJ::Pay::SelfPromo::History->update(); return $cart; @@ -729,6 +781,9 @@ sub create_shop_cart { my ( $class, $opts ) = @_; + LJ::Pay::SelfPromo->debug_msg( + "create_shop_cart called: " . LJ::compact_dumper($opts) ); + my $cart = LJ::Pay::Payment::new_cart( $opts->{'cart_owner'} ); my $it = LJ::Pay::Payment::PayItem->new_memonly( @@ -759,6 +814,12 @@ $it->set_prop( 'selfpromo_ditemid' => $entry->ditemid ); } + LJ::Pay::SelfPromo->debug_msg( + "create_shop_cart successful, " . + "payid=" . $cart->get_payid . ", " . + "piid=" . $it->get_piid + ); + return $cart; } @@ -939,6 +1000,21 @@ return LJ::statushistory_add( $promoter, $systemu, 'selfpromo', $message ); } +sub debug_msg { + my ( $class, @args ) = @_; + + return unless LJ::is_enabled('selfpromo_debug'); + + my $hostname = Sys::Hostname::hostname(); + my $time = localtime; + + my $msg = join( '', + "[shop/selfpromo, pid=$$, host=$hostname, time=$time] ", @args ); + + my ( $package, $filename, $line, $sub ) = caller(1); + warn "$msg in sub ${package}::${sub} at $filename line $line\n"; +} + package LJ::Pay::SelfPromo::Promo; use base qw( Class::Accessor ); @@ -992,41 +1068,58 @@ package LJ::Pay::SelfPromo::Lock; -my $locked = 0; - sub new { my ($class) = @_; - return if $locked; + LJ::Pay::SelfPromo->debug_msg("trying to acquire lock"); - die "Can't get lock" - unless LJ::get_lock( LJ::get_db_writer(), 'global', 'selfpromo' ); + if ( $LJ::REQ_GLOBAL{'selfpromo_locked'} ) { + LJ::Pay::SelfPromo->debug_msg("... already got it, skipping"); + return; + } - $locked = 1; + my $lock_result = + LJ::get_lock( LJ::get_db_writer(), 'global', 'selfpromo' ); + + unless ($lock_result) { + LJ::Pay::SelfPromo->debug_msg( + "LJ::get_lock returned false, throwing an exception" ); + die "Can't get lock"; + } + + LJ::Pay::SelfPromo->debug_msg("locked successfully"); + + $LJ::REQ_GLOBAL{'selfpromo_locked'} = 1; return bless {}, $class; } sub DESTROY { my ($self) = @_; + LJ::Pay::SelfPromo->debug_msg("releasing the lock"); + ## warning: this code may be called during exception "stack unwind" step. ## if original exception ($@) is not saved, it will be lost. local $@; LJ::release_lock( LJ::get_db_writer(), 'global', 'selfpromo' ); - $locked = 0; + $LJ::REQ_GLOBAL{'selfpromo_locked'} = 0; } sub taken { my ($class) = @_; - return LJ::lock_taken( LJ::get_db_writer(), 'global', 'selfpromo' ); + my $result = LJ::lock_taken( LJ::get_db_writer(), 'global', 'selfpromo' ); + LJ::Pay::SelfPromo->debug_msg("lock taken => $result"); + return $result; } sub taken_elsewhere { my ($class) = @_; - return !$locked && $class->taken; + my $result = ! $LJ::REQ_GLOBAL{'selfpromo_locked'} && $class->taken; + LJ::Pay::SelfPromo->debug_msg("lock taken elsewhere => $result"); + return $result; } 1;