/**
  * Main execute function for Refresh Inventory
  * 
  * @throws Exception
  */
 public function main()
 {
     $this->stdout->styles('backorder', ['text' => 'red']);
     $this->_now = date("Y-m-d H:i:s");
     $this->NsProductCount->useDbConfig = 'default';
     $this->NsLowItem->useDbConfig = 'default';
     // block until RefreshLowItemsShell releases the write lock
     $this->_waitForLock();
     // Because our join has a failover, it's not really a join on policy
     $productCounts = $this->NsProductCount->find('all', ['fields' => ["NsProductCount.*", "MAX(ItemAvailabilityTimes.start_date) AS LatestTime", "ItemAvailabilityTimes.item_availability_id", '(select count(*) from ns_low_items WHERE sku = NsBackorderPolicy.sku AND ns_warehouse_id = NsBackorderPolicy.ns_warehouse_id) as low_count'], 'group' => ["ItemAvailabilityTimes.item_id HAVING low_count < 1"], 'joins' => [['table' => 'ns_backorder_policies', 'alias' => 'NsBackorderPolicy', 'type' => 'INNER', 'conditions' => ['NsProductCount.sku = NsBackorderPolicy.sku', 'NsProductCount.ns_warehouse_id = NsBackorderPolicy.ns_warehouse_id']], ["table" => "items", "alias" => "Item", "type" => "INNER", "conditions" => ["NsProductCount.sku = Item.sku"]], ["table" => "item_availability_times", "alias" => "ItemAvailabilityTimes", "type" => "INNER", "conditions" => ["Item.id = ItemAvailabilityTimes.item_id", "ItemAvailabilityTimes.ns_warehouse_id = NsBackorderPolicy.ns_warehouse_id"]]], 'conditions' => ['NsProductCount.inventory_count - NsBackorderPolicy.unorderable_threshold < NsBackorderPolicy.backorder_threshold', 'ItemAvailabilityTimes.end_date IS NULL', 'ItemAvailabilityTimes.item_availability_id IN (2, 3)']]);
     $this->out('Processing ' . count($productCounts) . ' products.', 1, Shell::VERBOSE);
     // Add to the ns_low_items table
     foreach ($productCounts as $aProductCount) {
         $this->out("Working sku: {$aProductCount['NsProductCount']['sku']}...", 1, Shell::NORMAL);
         $policy = [];
         // Try to find an explicit policy
         $NsBackorderPolicy = $this->NsBackorderPolicy->find('first', ["conditions" => ["sku" => $aProductCount['NsProductCount']['sku'], "ns_warehouse_id" => $aProductCount['NsProductCount']['ns_warehouse_id']]]);
         if ($NsBackorderPolicy) {
             $policy = $NsBackorderPolicy['NsBackorderPolicy'];
         }
         if (!$policy) {
             throw new Exception("Failed to find policy for {$aProductCount['NsProductCount']['sku']}");
         }
         $this->NsLowItem->create();
         $this->NsLowItem->save(["sku" => $aProductCount['NsProductCount']['sku'], "ns_warehouse_id" => $aProductCount['NsProductCount']['ns_warehouse_id'], "inventory_count" => $aProductCount['NsProductCount']['inventory_count'], "item_availability_id" => $policy['backorder_item_availability_id'], "restock_date" => $policy['backorder_restock_date'], "threshold" => $policy['unorderable_threshold']]);
         $this->out("<backorder>I am notifying you of a low item!</backorder>", 1, Shell::NORMAL);
         $subject = "Low Inventory Alert";
         $word = $this->_iatToWord($policy['item_availability_id']);
         $message = "An item (SKU {$aProductCount['NsProductCount']['sku']}) is at risk of going into {$word} status.\n\n" . "To set this item's backorder policy, visit the following URL:\n" . "http://admin.youniqueproducts.com/admin3/warehouse.php#/warehouse/backorder\n\n" . "Message: {$policy['message']}\n\n" . "If you are not logged in, please first visit:\n" . "https://admin.youniqueproducts.com/admin3/index.php";
         SNS::sendSNS("Shipping_Issues", $subject, $message);
     }
     $this->_releaseLock();
 }
 /**
  * Execute DataFlowFour
  * @return bool
  */
 public function execute()
 {
     $this->out('Sending sns test.');
     try {
         SNS::sendSNS("Payment_Declines", 'Test', 'test message');
     } catch (Exception $e) {
         print $e->getCode() . "\n";
         print $e->getMessage() . "\n";
     }
     $this->out('Sent sns test.');
     return true;
 }
 public function main()
 {
     $this->__populateNsProductsCount();
     // We're looking for products that are in ns_product_counts but not in ns_backorder_defaults
     // Those rows won't be flagged when they run low on inventory
     $NsProductCount = $this->NsProductCount->find('all', ['fields' => ["NsProductCount.*", "NsBackorderDefault.*"], 'joins' => [['table' => 'ns_backorder_defaults', 'alias' => 'NsBackorderDefault', 'type' => 'LEFT', 'conditions' => ['NsProductCount.ns_warehouse_id = NsBackorderDefault.ns_warehouse_id', 'NsProductCount.sku = NsBackorderDefault.sku']]]]);
     var_export($NsProductCount);
     $orphanList = [];
     foreach ($NsProductCount as $aNsProductCount) {
         if (!$aNsProductCount['NsBackorderDefault']['id']) {
             $orphanList[] = ["sku" => $aNsProductCount['NsProductCount']['sku'], "ns_warehouse_id" => $aNsProductCount['NsProductCount']['ns_warehouse_id']];
         }
     }
     if ($orphanList) {
         $subject = "Missing Backorder Default Alert";
         $message = "At least one item is missing a backorder default policy.\n" . "Contact Don; we're sure he's just the one to fix this for you.\n\n";
         foreach ($orphanList as $orphan) {
             $message .= "SKU: {$orphan['sku']},\twarehouse id: {$orphan['ns_warehouse_id']}\n";
         }
         SNS::sendSNS("Shipping_Issues", $subject, $message);
     }
 }
 /**
  * Process Payments
  * @param string $referenceId
  * @param array $paymentMethods
  * @param bool $test_mode
  * @return array
  */
 public function processOrderPayments($referenceId, $paymentMethods, $test_mode = false)
 {
     syslog(LOG_DEBUG, "Order Payments   {$referenceId}    " . count($paymentMethods));
     $creditCards = [];
     $oxxoPayments = [];
     $giroPayments = [];
     $sofortPayments = [];
     $paypalPayments = [];
     $ledgerMethods = [];
     foreach ($paymentMethods as $payment) {
         switch ($payment['type']) {
             case OrderPayment::TYPE_LEDGER_NAME:
                 $ledgerMethods[] = $payment;
                 break;
             case OrderPayment::TYPE_CREDITCARD_NAME:
                 $creditCards[] = $payment;
                 break;
             case OrderPayment::TYPE_PAYPAL_NAME:
                 $paypalPayments[] = $payment;
                 break;
             case OrderPayment::TYPE_OXXO_NAME:
                 $oxxoPayments[] = $payment;
                 break;
             case OrderPayment::TYPE_GIRO_NAME:
                 $giroPayments[] = $payment;
                 break;
             case OrderPayment::TYPE_SOFORT_NAME:
                 $sofortPayments[] = $payment;
                 break;
         }
     }
     $processedPayments = [];
     try {
         if (count($ledgerMethods) > 0) {
             $this->ProductCredit = ClassRegistry::init('ProductCredit');
             foreach ($ledgerMethods as $payment) {
                 $result = $this->ProductCredit->authorize(ProductCredit::METHOD_SYSTEM, ProductCredit::TYPE_PURCHASE, Configure::read("market_id"), $payment['presenter_id'], $payment['user_id'], $payment['amount'], "System", $referenceId);
                 $payment['identifier'] = $payment['user_id'];
                 if ($result !== false) {
                     $payment['transaction_id'] = $result;
                     $payment['status'] = "authorized";
                     $processedPayments[] = $payment;
                 } else {
                     $payment['status'] = "failed";
                     $payment['transaction_id'] = "0";
                     return $this->voidTransactions($processedPayments, "Insufficient Product Credits");
                 }
             }
         }
         if (count($giroPayments) > 0) {
             foreach ($giroPayments as $payment) {
                 $mid = Configure::read('market_id');
                 $agent = $_SERVER['HTTP_USER_AGENT'];
                 //                    unset($payment['processor']);
                 //                    unset($payment['type']);
                 try {
                     $p = $payment;
                     $p['amount'] = $payment['amount']->amount;
                     $result = $this->WorldPayGiro->purchase($mid, $p, $agent, $test_mode);
                 } catch (WorldPayError $e) {
                     if ($e->getMessage() == WorldPay::$RESPONSE_ERROR) {
                         if ($this->WorldPayGiro->api->reply->hasError()) {
                             $response = $this->WorldPayGiro->api->reply;
                             $result = ['success' => false, 'error' => ['errno' => $response->err_code, 'errmsg' => $response->err_msgs]];
                         } else {
                             $result = ['success' => false, 'error' => ['errno' => '500', 'errmsg' => 'Server Error']];
                         }
                     } else {
                         $result = ['success' => false, 'error' => ['errno' => '401', 'errmsg' => 'Authentication Failed']];
                     }
                 }
                 if (!$result['success']) {
                     $payment['status'] = 'failed';
                     $error = " Code: " . $result['error']['errno'] . " Message: " . $result['error']['errmsg'];
                     if (!empty($result['error']['errno'])) {
                         // log to api log table
                         $this->ApiAudit = ClassRegistry::init('ApiAudit');
                         $api_data = ['reference_name' => get_class(), 'reference_id' => 0, 'source' => __FILE__ . ' ' . __LINE__, 'destination' => 'worldpay api', 'sent' => json_encode($payment), 'received' => $error, 'notes' => 'World Pay Giro fail'];
                         $this->ApiAudit->clear();
                         $this->ApiAudit->create($api_data);
                         $this->ApiAudit->save();
                     }
                     $error = __('There was a payment error. Please contact support.');
                     return $this->voidTransactions($processedPayments, $error);
                 } else {
                     // For giro save reference and redirect
                     $payment['status'] = "success";
                     $payment['redirect'] = true;
                     $payment['identifier'] = 0;
                     $payment['processor'] = PaymentComponent::GATEWAY_WORLDPAY_GIRO;
                     $payment['transaction_id'] = $result['reply']->response->reply->orderStatus->reference;
                     $processedPayments[] = $payment;
                 }
             }
         }
         if (count($sofortPayments) > 0) {
             foreach ($sofortPayments as $payment) {
                 $mid = Configure::read('market_id');
                 $agent = $_SERVER['HTTP_USER_AGENT'];
                 //                    unset($payment['processor']);
                 //                    unset($payment['type']);
                 try {
                     $p = $payment;
                     $p['amount'] = $payment['amount']->amount;
                     $result = $this->WorldPaySofort->purchase($mid, $p, $agent, $test_mode);
                 } catch (WorldPayError $e) {
                     if ($e->getMessage() == WorldPay::$RESPONSE_ERROR) {
                         if ($this->WorldPaySofort->api->reply->hasError()) {
                             $response = $this->WorldPaySofort->api->reply;
                             $result = ['success' => false, 'error' => ['errno' => $response->err_code, 'errmsg' => $response->err_msgs]];
                         } else {
                             $result = ['success' => false, 'error' => ['errno' => '500', 'errmsg' => 'Server Error']];
                         }
                     } else {
                         $result = ['success' => false, 'error' => ['errno' => '401', 'errmsg' => 'Authentication Failed']];
                     }
                 }
                 if (!$result['success']) {
                     $payment['status'] = 'failed';
                     $error = " Code: " . $result['error']['errno'] . " Message: " . $result['error']['errmsg'];
                     if (!empty($result['error']['errno'])) {
                         // log to api log table
                         $this->ApiAudit = ClassRegistry::init('ApiAudit');
                         $api_data = ['reference_name' => get_class(), 'reference_id' => 0, 'source' => __FILE__ . ' ' . __LINE__, 'destination' => 'worldpay api', 'sent' => json_encode($payment), 'received' => $error, 'notes' => 'World Pay Sofort fail'];
                         $this->ApiAudit->clear();
                         $this->ApiAudit->create($api_data);
                         $this->ApiAudit->save();
                     }
                     $error = __('There was a payment error. Please contact support.');
                     return $this->voidTransactions($processedPayments, $error);
                 } else {
                     // For sofort save reference and redirect
                     $payment['status'] = "success";
                     $payment['redirect'] = true;
                     $payment['identifier'] = 0;
                     $payment['processor'] = PaymentComponent::GATEWAY_WORLDPAY_SOFORT;
                     $payment['transaction_id'] = $result['reply']->response->reply->orderStatus->reference;
                     $processedPayments[] = $payment;
                 }
             }
         }
         if (count($oxxoPayments) > 0) {
             foreach ($oxxoPayments as $payment) {
                 $mid = Configure::read('market_id');
                 $agent = $_SERVER['HTTP_USER_AGENT'];
                 //                    unset($payment['processor']);
                 //                    unset($payment['type']);
                 try {
                     $p = $payment;
                     $p['amount'] = $payment['amount']->amount;
                     $result = $this->WorldPayOxxo->purchase($mid, $p, $agent, $test_mode);
                 } catch (WorldPayError $e) {
                     if ($e->getMessage() == WorldPay::$RESPONSE_ERROR) {
                         if ($this->WorldPayOxxo->api->reply->hasError()) {
                             $response = $this->WorldPayOxxo->api->reply;
                             $result = ['success' => false, 'error' => ['errno' => $response->err_code, 'errmsg' => $response->err_msgs]];
                         } else {
                             $result = ['success' => false, 'error' => ['errno' => '500', 'errmsg' => 'Server Error']];
                         }
                     } else {
                         $result = ['success' => false, 'error' => ['errno' => '401', 'errmsg' => 'Authentication Failed']];
                     }
                 }
                 if (!$result['success']) {
                     $payment['status'] = 'failed';
                     $error = " Code: " . $result['error']['errno'] . " Message: " . $result['error']['errmsg'];
                     if (!empty($result['error']['errno'])) {
                         // log to api log table
                         $this->ApiAudit = ClassRegistry::init('ApiAudit');
                         $api_data = ['reference_name' => get_class(), 'reference_id' => 0, 'source' => __FILE__ . ' ' . __LINE__, 'destination' => 'worldpay api', 'sent' => json_encode($payment), 'received' => $error, 'notes' => 'World Pay fail'];
                         $this->ApiAudit->clear();
                         $this->ApiAudit->create($api_data);
                         $this->ApiAudit->save();
                     }
                     $error = __('There was a payment error. Please contact support.');
                     return $this->voidTransactions($processedPayments, $error);
                 } else {
                     // For oxxo save reference and redirect
                     $payment['status'] = "success";
                     $payment['redirect'] = true;
                     $payment['identifier'] = 0;
                     $payment['processor'] = PaymentComponent::GATEWAY_WORLDPAY_OXXO;
                     $payment['transaction_id'] = $result['reply']->response->reply->orderStatus->reference;
                     $processedPayments[] = $payment;
                 }
             }
         }
         if (count($creditCards) > 0) {
             foreach ($creditCards as $payment) {
                 $payment['identifier'] = substr($payment['cardnum'], -4);
                 switch ($payment['processor']) {
                     case self::GATEWAY_WORLDPAY:
                         $currency = $this->WorldPay->getCurrency(Configure::read("market_id"));
                         $mid = Configure::read('market_id');
                         $agent = $_SERVER['HTTP_USER_AGENT'];
                         $data = ['amount' => $payment['amount']->amount, 'currency' => $currency, 'ip_address' => $payment['ip_address'], 'email' => $payment['email'], 'session_id' => $payment['session_id'], 'id' => $payment['orderId'], 'address' => $payment['billing'], 'card' => ['accountNumber' => $payment['cardnum'], 'expirationMonth' => $payment['cardExpMonth'], 'expirationYear' => $payment['cardExpYear'], 'cvv' => $payment['cardcode'], 'firstName' => $payment['firstName'], 'lastName' => $payment['lastName']]];
                         try {
                             $result = $this->WorldPay->purchase($mid, $data, $agent, $test_mode);
                         } catch (WorldPayError $e) {
                             if ($e->getMessage() == WorldPay::$RESPONSE_ERROR) {
                                 if ($this->WorldPay->api->reply->hasError()) {
                                     $response = $this->WorldPay->api->reply;
                                     $result = ['success' => false, 'error' => ['errno' => $response->err_code, 'errmsg' => $response->err_msgs]];
                                 } else {
                                     $result = ['success' => false, 'error' => ['errno' => '500', 'errmsg' => 'Server Error']];
                                 }
                             } else {
                                 $result = ['success' => false, 'error' => ['errno' => '401', 'errmsg' => 'Authentication Failed']];
                             }
                         }
                         if (!$result['success']) {
                             $payment['status'] = 'failed';
                             $error = " Code: " . $result['error']['errno'] . " Message: " . $result['error']['errmsg'];
                             if (!empty($result['error']['errno'])) {
                                 // log to api log table
                                 $this->ApiAudit = ClassRegistry::init('ApiAudit');
                                 unset($data['card']);
                                 $api_data = ['reference_name' => get_class(), 'reference_id' => 0, 'source' => __FILE__ . ' ' . __LINE__, 'destination' => 'worldpay api', 'sent' => json_encode($data), 'received' => $error, 'notes' => 'World Pay fail'];
                                 $this->ApiAudit->clear();
                                 $this->ApiAudit->create($api_data);
                                 $this->ApiAudit->save();
                             }
                             $error = __('There was a payment error. Please contact support.');
                             return $this->voidTransactions($processedPayments, $error);
                         } else {
                             $payment['status'] = "success";
                             $card_num = substr($result['reply']->response->reply->orderStatus->payment->cardNumber, -4);
                             $payment['identifier'] = $card_num;
                             $payment['transaction_id'] = $result['reply']->response->reply->orderStatus['orderCode'];
                             //World Pay : Credit Cards Only
                             if (substr($result['reply']->response->reply->orderStatus->payment->cardNumber, 0, 1) == '4') {
                                 //All Visa cards start with 4
                                 $payment['paid_with'] = 'visa';
                             } elseif (in_array(substr($result['reply']->response->reply->orderStatus->payment->cardNumber, 0, 2), ['51', '52', '53', '54', '55'])) {
                                 //All MasterCard cards start with either 51,52,53,54,55
                                 $payment['paid_with'] = 'mastercard';
                             }
                             $processedPayments[] = $payment;
                         }
                         break;
                     case self::GATEWAY_PAYPAL:
                         $result = $this->Paypal->process($referenceId, (string) $payment['amount'], $payment['firstName'], $payment['lastName'], $payment['billingpostalcode'], $payment['cardnum'], $payment['carexp'], $payment['cardcode']);
                         if ($result->Ack != "Success") {
                             $payment['status'] = "failed";
                             $payment['transaction_id'] = $result->TransactionID;
                             return $this->voidTransactions($processedPayments, $result->Errors->LongMessage);
                         } else {
                             $payment['transaction_id'] = $result->TransactionID;
                             $payment['status'] = "success";
                             $processedPayments[] = $payment;
                         }
                         break;
                     case self::GATEWAY_CYBERSOURCE:
                         $ip = array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
                         try {
                             if (strlen($payment['billingpostalcode']) > 10) {
                                 throw new Exception("billing postal code not valid.");
                             }
                         } catch (Exception $e) {
                             return false;
                         }
                         $billTo = array("email" => $payment['billingemail'], "city" => $payment['billingcity'], "firstName" => $payment['firstName'], "lastName" => $payment['lastName'], "postalCode" => $payment['billingpostalcode'], "state" => $payment['billingstate'], "street1" => $payment['billingaddress1'], "street2" => $payment['billingaddress2'], "country" => $payment['billingcountry'], "ipAddress" => $ip);
                         //format exp for cybersource
                         $exp_month = substr($payment['carexp'], 0, 2);
                         $exp_year = substr($payment['carexp'], 3, 4);
                         $card = array("accountNumber" => $payment['cardnum'], "expirationMonth" => $exp_month, "expirationYear" => $exp_year, "cvv" => $payment['cardcode']);
                         $purchaseTotals = array("grandTotalAmount" => (string) $payment['amount']);
                         $result = $this->Cybersource->purchase($billTo, $card, $purchaseTotals);
                         $payment['transaction_id'] = $result->requestID;
                         $payment['processor'] = OrderPaymentProcessor::PROCESSOR_CYBERSOURCE;
                         if ($result->reasonCode != 100) {
                             $payment['status'] = "failed";
                             return $this->voidTransactions($processedPayments, $this->Cybersource->reasonDescriptions[$result->reasonCode]);
                         } else {
                             $payment['status'] = "success";
                             $processedPayments[] = $payment;
                         }
                         break;
                     case self::GATEWAY_BRAINTREE:
                         $result = $this->Braintree->purchase($payment, $_POST['device_data']);
                         if (YOUNIQUE_TESTSERVER) {
                             CakeLog::debug(var_export($result, true));
                         }
                         if ($result->success) {
                             $payment['status'] = "success";
                             $payment['paid_with'] = '';
                             if (!empty($result->transaction->creditCardDetails->last4)) {
                                 $payment['identifier'] = $result->transaction->creditCardDetails->last4;
                                 if (substr($result->transaction->creditCardDetails->maskedNumber, 0, 1) == '4') {
                                     //All Visa cards start with 4
                                     $payment['paid_with'] = 'visa';
                                 } elseif (in_array(substr($result->transaction->creditCardDetails->maskedNumber, 0, 2), ['51', '52', '53', '54', '55'])) {
                                     //All MasterCard cards start with either 51,52,53,54,55
                                     $payment['paid_with'] = 'mastercard';
                                 }
                             } else {
                                 if (!empty($result->transaction->paypalDetails->paymentId)) {
                                     $payment['identifier'] = $result->transaction->paypalDetails->payerEmail;
                                     $payment['paid_with'] = 'paypal';
                                 } else {
                                     $payment['identifier'] = $result->transaction->id;
                                 }
                             }
                             $payment['transaction_id'] = $result->transaction->id;
                             $processedPayments[] = $payment;
                         } else {
                             if (isset($result->errors)) {
                                 $errors = $result->errors->deepAll();
                             }
                             if (!empty($errors)) {
                                 // errors can be referenced here:
                                 // https://developers.braintreepayments.com/javascript+php/sdk/server/transaction-processing/validations
                                 $api_errors = $result->errors->deepAll();
                                 $errors = [];
                                 foreach ($api_errors as $key => $value) {
                                     $errors[] = $value->message;
                                 }
                                 $internal_use_error = implode(" ", $errors);
                                 $error = __('There was an error. Please contact support.');
                                 // log to api log table
                                 $this->ApiAudit = ClassRegistry::init('ApiAudit');
                                 $api_data = ['reference_name' => get_class(), 'reference_id' => 0, 'source' => __FILE__ . ' ' . __LINE__, 'destination' => 'braintree api', 'sent' => json_encode($this->Braintree->payment_data), 'received' => $internal_use_error, 'notes' => 'Braintree validation fail'];
                                 $this->ApiAudit->clear();
                                 $this->ApiAudit->create($api_data);
                                 $this->ApiAudit->save();
                             } else {
                                 // decline
                                 /**
                                  * Error overwrites as per Michael Gulbrandsen
                                  */
                                 switch ($result->transaction->processorResponseCode) {
                                     case 1000:
                                         $error = "We are unable to process your transaction given the " . "information provided. Please provide an alternate form of " . "payment or reach out to your bank for more information.";
                                         break;
                                     case 3000:
                                         $error = "We're sorry, we cannot process your transaction " . "at this time. Please try again.";
                                         break;
                                     default:
                                         $subject = "BrainTree Payment Decline";
                                         $error = "We are unable to process your transaction given the " . "information provided. Please provide an alternate form of " . "payment or reach out to your bank for more information.";
                                         $message = "Status: " . $result->transaction->status . " Code: " . $result->transaction->processorResponseCode . " Message: " . $result->transaction->processorResponseText . "\n";
                                         $message .= var_export($result, true);
                                         SNS::sendSNS("Payment_Declines", $subject, $message);
                                         break;
                                 }
                             }
                             return $this->voidTransactions($processedPayments, $error);
                         }
                         break;
                     default:
                         return FALSE;
                         break;
                 }
             }
         }
         if (count($paypalPayments) > 0) {
             foreach ($paypalPayments as $payment) {
                 $expressPayment = $this->Paypal->getExpressCheckout($payment['token']);
                 //need to return token, paypal user id, amount, and currency
                 $token = $expressPayment->GetExpressCheckoutDetailsResponseDetails->Token;
                 $payerId = $expressPayment->GetExpressCheckoutDetailsResponseDetails->PayerInfo->PayerID;
                 $amount = $expressPayment->GetExpressCheckoutDetailsResponseDetails->PaymentDetails->OrderTotal->value;
                 $currency = $expressPayment->GetExpressCheckoutDetailsResponseDetails->PaymentDetails->OrderTotal->currencyID;
                 //can compare payer userid, amount, currency to validate transaction here if needed
                 //also could make sure the receiving acct is correct
                 $result = $this->Paypal->doExpressCheckout($token, $payerId, $amount, $currency);
                 $payment['identifier'] = $payment['user_id'];
                 if ($result->Ack != "Success") {
                     $payment['status'] = "failed";
                     if (isset($result->TransactionID)) {
                         $payment['transaction_id'] = $result->TransactionID;
                     }
                     return $this->voidTransactions($processedPayments, $result->Errors->LongMessage);
                 } else {
                     $payment['transaction_id'] = $result->DoExpressCheckoutPaymentResponseDetails->PaymentInfo->TransactionID;
                     $payment['status'] = "success";
                     $processedPayments[] = $payment;
                 }
             }
         }
         foreach ($processedPayments as $key => $payment) {
             if ($processedPayments[$key]['type'] == OrderPayment::TYPE_LEDGER_NAME) {
                 $this->ProductCredit->capture($processedPayments[$key]['presenter_id'], $processedPayments[$key]['user_id'], $processedPayments[$key]['transaction_id']);
                 $processedPayments[$key]['status'] = "success";
             }
         }
     } catch (Exception $e) {
         if (YOUNIQUE_TESTSERVER != true) {
             YouniqueEmail::queueEmail(['date' => date('Y-m-d H:i:s'), 'reference_id' => $referenceId, 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString()], 'admin/paymentfailure', '*****@*****.**', 'Payment failure', 'paymentFailure', 'en_US');
         }
         return ["success" => false];
     }
     return ["success" => true, "payments" => $processedPayments];
 }
 /**
  * Send Sns Alert
  *
  * @param $message
  * @param null $subject
  */
 protected function sendSnsAlert($message, $subject = null)
 {
     if (empty($subject)) {
         $subject = "{$this->sqs_name} SQS Alert";
     }
     $message = "An alert has been triggered for {$this->sqs_name}.\n\n" . "{$message}\n\n" . "SQS message available in queue: \n" . $this->primarySqsUrl() . "\n" . "https://younique.signin.aws.amazon.com/console";
     try {
         SNS::sendSNS($this->sns_topic, $subject, $message);
     } catch (Exception $e) {
         $this->logMsg("SNS Topic {$this->sns_topic} not configured correctly.", false, true);
     }
 }
 /**
  * Send Sns Error message
  *
  * @param $message
  */
 private function sendErrorMessage($message)
 {
     $subject = "Foundation Donation Cron Failed";
     $message = ".\n" . $message . "\n";
     SNS::sendSNS("crons", $subject, $message);
 }
Exemple #7
0
 /**
  * Invoked when a 400 response is received from Snap due to a missing SKU
  */
 private function _nonExistentItemProcessing()
 {
     //Delete order from Snap
     $this->deleteShipment($this->snap_order['ShipmentId']);
     //Send to Amazon SNS Service (email, SMS, Slack)
     $subject = "Snap API Missing Sku Alert ORD# {$this->snap_order['CustomerRef']}";
     $message = "Failed to update Snap, API responded with 400 - bad SKUid item missing\n" . "View Order: https://admin.youniqueproducts.com/admin3/orders.php?order_id={$this->snap_order['CustomerRef']}";
     SNS::sendSNS("Logistics_Alert", $subject, $message);
     //Put order in new 'Order Shipment Status' (9) called "Incomplete order in WMS"
     $this->OrderShipment->clear();
     $this->OrderShipment->id = $this->snap_order['ShipmentId'];
     $this->OrderShipment->saveField("order_shipment_status_id", OrderShipmentStatus::INCOMPLETE_ORDER_WMS);
     $this->OrderShipment->saveField("order_id", $this->snap_order['CustomerRef']);
     //Add to order log
     $this->UserNote->clear();
     $this->UserNote->save(['user_id' => $this->user_id, 'note' => "Removed shipment from Snap, sent error to Logistics team, set shipment to 'WMS Incomplete'", 'reference_type' => 'order', 'reference_id' => $this->snap_order['CustomerRef'], 'user_note_status' => 'normal']);
 }
 /**
  * Main execute function of Refresh Low Items Shell
  */
 public function main()
 {
     $this->stdout->styles('backorder', ['text' => 'red']);
     $this->_waitForLock();
     $this->_startDateTime = date("Y-m-d H:i:s", strtotime('-30 minutes'));
     $now = date("Y-m-d H:i:s");
     $this->ItemAvailabilityTimes->useDbConfig = 'default';
     /**
      * This sets availability to be true (Just send email)
      * or false item availability gets set to backorder.
      */
     $this->_disableSetAvailability = $this->args['0'] == "enable" ? false : true;
     if ($this->_disableSetAvailability) {
         $this->out('Setting Item Availability is disabled. Emails only.', 1, Shell::VERBOSE);
     } else {
         $this->out('Setting Item Availability is enabled.', 1, Shell::VERBOSE);
     }
     // read data from low_items
     $NsLowItem = $this->NsLowItem->find('all', []);
     $this->out("Processing " . count($NsLowItem) . " Low Items.", 1, Shell::VERBOSE);
     foreach ($NsLowItem as $aNsLowItem) {
         // get the number of order items since startDateTime
         $OrderItem = $this->OrderItem->find('all', ['fields' => ['SUM(OrderItem.quantity) AS BBQ', 'OrderItem.item_id'], 'joins' => [['table' => 'items', 'alias' => 'Item', 'type' => 'INNER', 'conditions' => ['OrderItem.item_id = Item.id']]], 'conditions' => ['Item.sku' => $aNsLowItem['NsLowItem']['sku'], 'OrderItem.date_created >=' => $this->_startDateTime, 'OrderItem.ns_warehouse_id' => $aNsLowItem['NsLowItem']['ns_warehouse_id']], 'group' => ['OrderItem.item_id']]);
         $this->out("SKU:       " . $aNsLowItem['NsLowItem']['sku'], 1, Shell::NORMAL);
         $this->out("Inv Count: " . $aNsLowItem['NsLowItem']['inventory_count'], 1, Shell::NORMAL);
         $this->out("Agg Quant: " . (int) $OrderItem[0][0]['BBQ'], 1, Shell::NORMAL);
         $this->out("Threshold: " . $aNsLowItem['NsLowItem']['threshold'], 1, Shell::NORMAL);
         $this->out('Order item count: ' . (int) $OrderItem[0][0]['BBQ']);
         $this->NsLowItem->updateAll(['NsLowItem.order_count' => $OrderItem[0][0]['BBQ']], ['NsLowItem.id' => $aNsLowItem['NsLowItem']['id']]);
         if ($aNsLowItem['NsLowItem']['inventory_count'] - (int) $OrderItem[0][0]['BBQ'] < $aNsLowItem['NsLowItem']['threshold']) {
             // implement back order policy
             // See if the item is already unavailable
             $redundantItem = $this->Item->find('first', ['conditions' => ['Item.sku' => $aNsLowItem['NsLowItem']['sku']]]);
             $isAvailable = $this->Item->getIsAvailableById($redundantItem['Item']['id']);
             if (!$isAvailable) {
                 continue;
             }
             if (!$this->_disableSetAvailability) {
                 $this->ItemAvailabilityTimes->updateAll(['end_date' => '"' . trim($now) . '"'], ['ItemAvailabilityTimes.item_id' => $redundantItem['Item']['id'], 'ItemAvailabilityTimes.ns_warehouse_id' => $aNsLowItem['NsLowItem']['ns_warehouse_id'], 'ItemAvailabilityTimes.end_date IS NULL']);
                 $this->ItemAvailabilityTimes->clear();
                 $this->ItemAvailabilityTimes->create();
                 $this->ItemAvailabilityTimes->save(['item_id' => $redundantItem['Item']['id'], 'item_availability_id' => $aNsLowItem['NsLowItem']['item_availability_id'], 'ns_warehouse_id' => $aNsLowItem['NsLowItem']['ns_warehouse_id'], 'estimated_date' => $aNsLowItem['NsLowItem']['restock_date'], 'start_date' => $now]);
                 $setAvailabilityMessage = 'Set Availability is enabled the product: ' . $aNsLowItem['NsLowItem']['sku'] . ' has been set to backorder.';
                 /**
                  * Clean up product count
                  */
                 $this->NsLowItem->clear();
                 $this->NsLowItem->delete($aNsLowItem['NsLowItem']['id']);
             } else {
                 $setAvailabilityMessage = "Set Availability is disabled only notification was sent no action was taken.\n\n";
             }
             // tell an adult
             $this->out("<backorder>I am notifying you of a back-order policy implementation!</backorder>", 1, Shell::NORMAL);
             $subject = "Backorder Policy Implementation Alert";
             $word = $this->_iatToWord($aNsLowItem['NsLowItem']['item_availability_id']);
             $message = "An item (SKU {$aNsLowItem['NsLowItem']['sku']}) has gone into {$word} status.\n\n" . $setAvailabilityMessage . "\n" . "To look at backorder policies, visit the following URL:\n" . "https://admin.youniqueproducts.com/admin3/warehouse.php#/warehouse/backorder\n\n" . "If you are not logged in, please first visit:\n" . "https://admin.youniqueproducts.com/admin3/index.php";
             SNS::sendSNS("Shipping_Issues", $subject, $message);
         }
     }
     $this->_releaseLock();
 }
 /**
  * Send Error SNS
  * @param $order_id
  * @param $error_data
  */
 private function sendError($order_id, $error_data)
 {
     $subject = "Shipment Method Error Alert";
     $message = "Setting shipment method failed [order_id: {$order_id}].\n" . "Message: \n" . var_export($error_data, true);
     SNS::sendSNS("Order_Queue_Issues", $subject, $message);
 }
Exemple #10
0
 public function natesSns()
 {
     $subject = "Snap API Missing Sku Alert ORD# xxxxxx";
     $message = "Failed to update Snap, API responded with 400 - bad SKUid item missing\n" . "https://admin.youniqueproducts.com/admin3/orders.php?order_id=xxxxx";
     SNS::sendSNS("Logistics_Alert", $subject, $message);
     $this->out("<error> sending out test </error>");
 }
 public function sendSnsEmail()
 {
     if ($_SERVER['REMOTE_ADDR'] == "127.0.0.1") {
         $data = $this->request->data;
         if (empty($data['resource']) || empty($data['subject']) || empty($data['message'])) {
             $result = 'Please supply a resource, subject and message.';
         } else {
             $response = SNS::sendSNS($data['resource'], $data['$subject'], $data['message']);
             $result = $response;
         }
         $this->set(array('result' => $result, '_serialize' => ['result']));
     }
 }
 /**
  * Pay Retail Commission
  *
  * Used by Commission Sqs Queue to pay commissions
  *
  * @param $commission
  * @param null $queue_message
  * @see PayCommissionTask
  * @see CommissionSqsShell
  * @see QueueCommissionsTask
  * @return bool|mixed|stdClass
  */
 public function payRetailCommission($commission, &$queue_message = null)
 {
     $config = array();
     $config_file = parse_ini_file("/etc/younique/payquicker.ini", true);
     $address = $this->Presenter->loadAddressDetails($commission['presenter_id']);
     $state_code = $address['User']['Address']['State']['abbrev'];
     $country_code = $address['User']['Address']['Country']['country_code'];
     $us_domestic = FALSE;
     switch ($commission['currency']) {
         case 'USD':
             if (in_array($state_code, $this->us_territories)) {
                 $config['payquicker'] = $config_file['USD_INT'];
             } else {
                 $config['payquicker'] = $config_file['USD_DOM'];
             }
             $us_domestic = TRUE;
             break;
         case 'CAD':
             $config['payquicker'] = $config_file['CAD'];
             break;
         case 'AUD':
             $config['payquicker'] = $config_file['AUD'];
             break;
         case 'NZD':
             //NZD Gets paid from the USD international account
             $config['payquicker'] = $config_file['NZD'];
             break;
         case 'GBP':
             $config['payquicker'] = $config_file['GBP'];
             break;
         case 'EUR':
             $config['payquicker'] = $config_file['EUR'];
             break;
         case 'MXN':
             $config['payquicker'] = $config_file['MXN'];
             break;
         default:
             // this should never happen
             $this->apiLog("royalties_earned.id", $commission['id'], "RoyaltiesEarned->payRetailCommission", "PayQuicker API", var_export($commission, true), "", "Could not load config for this currency", 1);
             error_log("Could not load config for this currency");
             return FALSE;
             break;
     }
     $this->Presenter->RoyaltiesEarned->id = $commission['id'];
     //Withhold appropriate taxes:
     switch ($commission['market_id']) {
         case 6:
             //Mexico
             $commission = $this->withholdMexicoTaxes($commission);
             break;
         case 8:
             //France
             $payFr = $this->payFranceCommissions($commission['presenter_id']);
             if (strtoupper($payFr) == 'VDI') {
                 $commission = $this->withholdFranceTaxes($commission);
             }
             break;
         default:
             break;
     }
     App::uses("PayquickerAPI", "Lib");
     $royalties_withheld = $this->Presenter->getDynamicData($commission['presenter_id'], 'royalties_withheld');
     if (isset($royalties_withheld[0]) && $royalties_withheld[0]['value'] == 1) {
         $this->Presenter->RoyaltiesEarned->saveField("reference_id", 'Royalties_Withheld');
         return 'Royalties_Withheld';
     }
     $dateEarned = $commission['date_earned'];
     $dateExpires = date("m/d/Y", strtotime("next year", strtotime($dateEarned)));
     $orderId = $commission['order_id'];
     $payeeName = $commission['first_name'];
     $recipientEmail = $commission['payquickeremail'];
     $paymentObject = array("authorizedKey" => $config['payquicker']['authorizedKey'], "senderEmail" => $config['payquicker']["senderEmail"], "recipientEmail" => $recipientEmail, "amount" => $commission['amount'], "comment" => "Hi {$payeeName}, This is your retail royalty for order #{$orderId}.  Congratulations! We are proud of your online success.", "expirationDate" => $dateExpires, "forceDebitCard" => $commission['forceCard'], "accountingId" => $orderId, "currency" => $commission['currency'], "countryCode" => $country_code);
     if ($us_domestic === TRUE) {
         $paymentObject['stateCode'] = $state_code;
     }
     $this->Presenter->RoyaltiesEarned->saveField("date_attempted", date("Y-m-d H:i:s"));
     /**
      * Empty amounts should not be tried against payquicker
      * and are set to paid status
      */
     if (empty($paymentObject['amount'])) {
         $this->Presenter->RoyaltiesEarned->saveField("date_paid", date("Y-m-d H:i:s"));
         $this->Presenter->RoyaltiesEarned->saveField("royalty_status_id", RoyaltiesEarned::STATUS_IS_PAID);
         return true;
     }
     if (YOUNIQUE_TESTSERVER === true) {
         $response = new stdClass();
         $response->success = true;
         $response->reference = 'QATesting:' . $commission['order_id'];
     } else {
         $response = PayquickerAPI::call("instantPayment", $paymentObject);
     }
     if ($response->success == true) {
         $this->Presenter->RoyaltiesEarned->saveField("date_paid", date("Y-m-d H:i:s"));
         $this->Presenter->RoyaltiesEarned->saveField("reference_id", $response->reference);
         $this->Presenter->RoyaltiesEarned->saveField("royalty_status_id", RoyaltiesEarned::STATUS_IS_PAID);
     } else {
         /**
          * If error is duplicate update royalties earned data
          * if it is not already set.
          */
         if (!empty($response) && isset($response->status)) {
             if ($response->status == 'Duplicate') {
                 $duplicate = $this->find('first', ['conditions' => ['RoyaltiesEarned.id' => $commission['id']]]);
                 if (empty($duplicate['RoyaltiesEarned']['date_paid'])) {
                     $this->Presenter->RoyaltiesEarned->saveField("date_paid", date("Y-m-d H:i:s"));
                 }
                 if (empty($duplicate['RoyaltiesEarned']['reference_id'])) {
                     $this->Presenter->RoyaltiesEarned->saveField("reference_id", $response->reference);
                 }
                 if (empty($duplicate['RoyaltiesEarned']['royalty_status_id'])) {
                     $this->Presenter->RoyaltiesEarned->saveField("royalty_status_id", RoyaltiesEarned::STATUS_IS_PAID);
                 }
                 return true;
             }
         }
         /**
          * Send pay quicker error only once
          */
         if (!empty($queue_message) && empty($queue_message['failure'])) {
             $queue_message['failure'] = $response;
             // Remove the key since this is going into an email
             unset($paymentObject['authorizedKey']);
             $message_body = "There was an error posting a retail commission, here are the details:\n\n" . var_export($paymentObject, true) . "\n\nHere is the response we got:\n\n" . var_export($response, true);
             SNS::sendSNS('PayQuicker_Issues', "Failure to Pay Retail Commission [{$recipientEmail}]", $message_body);
         }
         /**
          * Return true status on state code failure
          * so queue will not retry it.
          */
         if (!empty($response) && isset($response->errorMessage)) {
             if ($response->errorMessage == 'stateCode is Required.') {
                 return true;
             }
         }
         return false;
     }
     return $response;
 }
 /**
  * Send Sns Error message
  *
  * @param $message_id
  * @param $receipt
  * @param $err
  */
 private function sendErrorMessage($message_id, $receipt, $err)
 {
     $subject = "{$this->queue_name} Queue Alert";
     $message = "A {$this->queue_name} Task has failed [message_id: {$message_id}].\n" . "Message: \n" . "{$err}\n" . "Queue message available in queue: " . AWS_ORDERS_SQS_URL . "\n" . "[\n" . " message_id: {$message_id}\n" . " receipt: {$receipt} \n" . "]\n" . "https://younique.signin.aws.amazon.com/console";
     SNS::sendSNS($this->sns_name, $subject, $message);
 }
 /**
  * Send Sns Error message
  *
  * @param $message_id
  * @param $receipt
  * @param $err
  */
 private function sendErrorMessage($message_id, $receipt, $err)
 {
     $subject = "Email Queue Alert";
     $message = "An Email Queue Task has failed [message_id: {$message_id}].\n" . "Message: \n" . "{$err}\n" . "Message data available in table:  " . $this->table . "\n" . "Queue message available in queue: " . $this->queue . "\n" . "[\n" . " message_id: {$message_id}\n" . " receipt: {$receipt} \n" . "]\n" . "https://younique.signin.aws.amazon.com/console";
     SNS::sendSNS("Order_Queue_Issues", $subject, $message);
 }