How can I get the subscription back from a Recurly Purchase? - php

I am building a custom checkout with the Recurly PHP Client. Since we use our own gateway logic, we are forced to use the Create Purchase method, as opposed to Create Subscription (as Create Subscription doesn't accept gateway_code as a parameter). Create Subscription returns the created subscription - easy!
But Create Purchase returns an Invoice Collection. It's possible to tease this apart to find the newly-created $subscription object but this hardly seems like the intended process. Is there (hopefully) a cleaner way of going about it?
My method for purchasing is as follows - see code comments.
protected static function create_subscription( $user_id, $args ) {
$result = false;
$purchase = new Recurly_Purchase();
$purchase->currency = $args['currency'];
$purchase->collection_method = 'automatic';
$purchase->gateway_code = $args['gateway_code'];
$account = new Recurly_Account( $user_id );
$account->email = $args['email'];
$account->first_name = $args['billing_first_name'];
$account->last_name = $args['billing_last_name'];
$account->vat_number = $args['vat_number'];
$billing_info = new Recurly_BillingInfo();
$billing_info->token_id = $args['recurly_token'];
$account->billing_info = $billing_info;
$purchase->account = $account;
$subscription = new Recurly_Subscription();
$subscription->plan_code = $args['plan_code'];
$purchase->subscriptions = array( $subscription );
try {
// "invoice" is the method to transact a Recurly_Purchase.
$purchase = Recurly_Purchase::invoice( $purchase );
if( $purchase instanceof Recurly_InvoiceCollection ) {
// this seems incredibly janky and error-prone
$result = reset( $purchase->charge_invoice->line_items )->subscription->get();
}
} catch ( Exception $e ) {
$result = $e;
}
// I need this to return the $subscription object generated by the purchase
return $result;
}

When you create a subscription, a successful response will include the UUID for that subscription. I am not a PHP developer but it might look something like this:
$subscription = new Recurly_Subscription();
$subscription->plan_code = $args['plan_code'];
$subscription->account = $account;
$subscription->currency = $args['currency'];
$subscription->create();
$uuid = isset($subscription->uuid);
$result = Recurly_Subscription::get($uuid);
return $result;
Also, please note that as of Recurly API version 2.17+ you can now pass gateway_code as a body param to create subscription AND create purchase as you initially hoped to do. Here is a link to the Recurly API Release notes, which indicates when the change was made.

Related

Shopware 6 change shipping method programmatically in checkout on order submission

I have two of same shipping methods with different price matrix, depending on customer distance, one of the two shipping method should be selected. This has to be done programmatically on checkout order confirmation, I looked at the cart collector, but it's about changing price of an item. I didn't find anything covered in documentation regarding shipping method change.
Following is my attempt to change it onOrderValidation.
private function getShippingMethod(string $id, Context $context): ?ShippingMethodEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter("id", $id));
$criteria->setLimit(1);
$result = $this->shippingMethodRepository->search($criteria, $context);
return $result->getEntities()->first();
}
public function onOrderValidation(BuildValidationEvent $event)
{
$cart = $this->cartService->getCart($this->salesChannelContext->getToken(), $this->salesChannelContext);
$delivery = $cart->getDeliveries()->first();
//test
$shippingMethod = $this->getShippingMethod($this->getShippingMethodZoneXId(), $event->getContext());
$delivery->setshippingMethod($shippingMethod);
$cartDeliveries = new DeliveryCollection();
$cartDeliveries->add($delivery);
$cart->addDeliveries($cartDeliveries);
$this->cartService->setCart($cart);
...
}
In the above code I have cart object, and delivery. I get the shipping method which I need to set, but it doesn't get updated.
Also i need to recalculate shipping price, what is the correct way to do it. any suggestion will be appreciated.
Update: I have also tried from shopware doc collect/process, but that also didn't work.
public function collect(CartDataCollection $data, Cart $original, SalesChannelContext $context, CartBehavior $behavior): void
{
$shippingMethod = $this->getShippingMethod($this->getShippingMethodZoneXId(), $context->getContext());
$shippingMethodId = $shippingMethod->getId();
$key = self::buildShippingKey($shippingMethodId);
$data->set($key, $shippingMethod);
}
public function process(CartDataCollection $data, Cart $original, Cart $toCalculate, SalesChannelContext $context, CartBehavior $behavior): void
{
// change delviery
$deliveries = $this->builder->build($toCalculate, $data, $context, $behavior);
$deliveryOriginal = $deliveries->first();
if($deliveryOriginal === null) {
return;
}
$shippingMethod = $this->getShippingMethod($this->getShippingMethodZoneXId(), $context->getContext());
$deliveries->first()->setShippingMethod($shippingMethod);
$this->deliveryCalculator->calculate($data, $toCalculate, $deliveries, $context);
$toCalculate->setDeliveries($deliveries);
}
I completely ended up with another approach, none of the above seem to work for me. Item price updation was taking place but not shipment.
So here's what you need, this contextSwitcher dependency i injected and it did the job. update() method that can be used to switch shipment method.
SalesChannelContextSwitcher $contextSwitcher,

Looping through multiple pages of a JSON request (Guzzle, Laravel, PHP)

New dev here so I am sorry if this is a simple question or something like that but haven't been able to find exactly what I am looking for (it totally could be that I am not asking the question correctly either) Basically I have a paginated list coming back from an api and I am not sure what the logic would be to be able to cycle through those pages. Here is the code that I have so far that works perfectly for the first page lol.
public function handle()
{
//This is the artisan command that runs on a timer and gets all the ticket and update fields that are needed and saves them to the database.
$tickets = $this->pullTicketSummary();
collect($tickets['data'])
->each(function ($currTicket) {
$ticketRow = Tickets::query()->firstOrCreate(['ticket_id' => $currTicket['id']]);
$ticketRow->status_id = $currTicket['status']['id'];
$ticketRow->category_id = $currTicket['category']['id'];
$ticketRow->user_id = $currTicket['assigned_to']['id'];
$ticketRow->jira_issue_id = $currTicket['jira_issue_id'];
$ticketRow->save();
collect($currTicket['updates'])->each(function ($update) use ($currTicket){
$updateRow = Update::query()->firstOrCreate(['update_id' => $update['update_id']]);
$updateRow->ticket_id = $currTicket['id'];
$updateRow->assignee_change = $update['assignee_change'];
});
});
Log::info('All tickets and updates were pulled successfully');
}
protected function pullTicketSummary()
{ //Function makes the guzzle request and returns the response from the happyfox api
$client = new Client();
$request = $client->get('https://happyfox.com/api/1.1/json/tickets/?size=50&page=1',
['auth' => ['N/A']);
$response = json_decode($request->getBody()->getContents(), true);
return $response;
}
With the fact that I am new if this is something that has been answered before that I missed please just shoot me over a link or if you are aware of any documentation that would help me get to the answer on my own that would be awesome! thanks!
Update your function to use the page number:
protected function pullTicketSummary($page)
{ //Function makes the guzzle request and returns the response from the happyfox api
$client = new Client();
$request = $client->get('https://happyfox.com/api/1.1/json/tickets/?size=50&page='.$page,
['auth' => ['N/A']);
$response = json_decode($request->getBody()->getContents(), true);
return $response;
}
//new function only to save the data from tickets variable. Necessary to reuse.
public function saveTicketsOrSomething($tickets)
{
collect($tickets['data'])
->each(function ($currTicket) {
$ticketRow = Tickets::query()->firstOrCreate(['ticket_id' => $currTicket['id']]);
$ticketRow->status_id = $currTicket['status']['id'];
$ticketRow->category_id = $currTicket['category']['id'];
$ticketRow->user_id = $currTicket['assigned_to']['id'];
$ticketRow->jira_issue_id = $currTicket['jira_issue_id'];
$ticketRow->save();
collect($currTicket['updates'])->each(function ($update) use ($currTicket){
$updateRow = Update::query()->firstOrCreate(['update_id' => $update['update_id']]);
$updateRow->ticket_id = $currTicket['id'];
$updateRow->assignee_change = $update['assignee_change'];
});
});
}
Then iterate until you finish all the pages:
$tickets = $this->pullTicketSummary(1); //first time
$numPages = $tickets['numPages']; //update here to get the actual value of number of pages
$this->saveTicketsOrSomething($tickets);
for ($i = 2; $i < $numPages; $i++) { //start on 2, cause we already have fetched page 1
$tickets = $this->pullTicketSummary($i); //other pages
$this->saveTicketsOrSomething($tickets);
}
Log::info('All tickets and updates were pulled successfully');

OctoberCMS - How to call a function inside a component

I am building an order form and I warn you in advance I am a noob with backend dev :)
So my first component takes all data from the order form and saves it to the database, then I use this same data to generate a quote. After this I have a thrird part which generates the invoice if the quote is accepted, so far my code looks like this:
// this runs when order is submitted on front end (runs from same component)
public function onAddOrder() {
$this->submitOrder();
$this->submitQuote();
Flash::success('Order successfully submitted!');
return Redirect::to('/home');
}
public function submitOrder() {
// Add it to the database
$order = new Order();
$order ->quote_no = $this->generateQuoteNo();
$order ->company_name = Input::get('company_name');
$order ->client_name = Input::get('client_name');
$order ->client_email = Input::get('client_email');
$order ->emergency_contact = Input::get('emergency_contact');
$order ->due_date = Input::get('due_date');
$order ->project_name = Input::get('project_name');
$order ->quote_query = Input::get('quote_query');
$order ->order_no = Input::get('order_no');
$order ->order_type = Input::get('order_type');
$order ->save();
}
}
public function submitQuote() {
$quote = new Quote();
$quote->quote_no = $this->generateQuoteNo();
$quote->customer = Input::get('company_name');
$quote->job_name = Input::get('project_name');
$quote->order_no = Input::get('order_no');
$quote->proof_price = $this->calculateProofPrice();
$quote->sub_total = $this->calculateSubTotal();
$quote->vat = $this->calculateVat();
$quote->total = $this->calculateTotal();
$quote->save();
}
This works fine but then I would like to run another function if a selection is made but this component is under a different class and I am not sure how to reference it.
if (Input::get('quote_query') === 'Order') {
$this->AcmeInvoice->onSubmitInvoice();
}
If someone could help me to fire the public function onSubmitInvoice() I will really appreciate it.
You can instantiate the object in the class & fire it off? eg: $invoice = new AcmeInvoice(); //add namespace if not in the name space; $invoice->onSubmitInvoice();
if (Input::get('query') === 'Invoice') {
$invoice = new AcmeInvoice();
$invoice->onSubmitInvoice('quote_no');
}

Yii2 - save() doesn't save

I have Order model, and I want to change "status" in one of orders. I execute such a code:
$order = new Order();
$new = $order->find()->where(['status' => 'new'])->orderBy(['id' => SORT_ASC])->one();
if($new){
$new->status = "queued";
$ok = $new->save();
return true;
}
And, $new is the record that I want, so that's ok. So, when I try to save changes, it doen't do it, and $ok gives me "false". I have no idea why, I have used save() before and never have problems with it.
Update:
Found mistake, it was not connected to save() function.
Your value is not saving because of model validation, You can skip model validation by putting false.
$order = new Order();
$new = $order->find()->where(['status' => 'new'])->orderBy(['id' => SORT_ASC])->one();
if($new){
$new->status = "queued";
$ok = $new->save(false); // skip model validation
return true;
}

Magento Order Creation Programatically only working on one shipping method

I am using the code below as part of a script to create Magento Orders programatically. The script works fine when I use
freeshipping_freeshipping
as the shipping method. However, when I choose any other shipping method such as a custom shipping method,flatrate_flatrate or usps_1 e.t.c, it gives me the error:
"Please Specify a shipping method"
I have searched everywhere but was unable to find a solution. Any help would be highly appreciated, thanks.
$shippingAddress->setCollectShippingRates(true)->collectShippingRates()
->setShippingMethod($shipping_method);
Edit:
I got it to work with flatrate for non US orders and an extension freeadminshipping on both US and non US orders. However, still unable to use any of the UPS or USPS shipping methods.
This method create Order and I have use this in my project it working. In your code please remove shipping method set code and try I hope that work fine for you. otherwise you can use below my code.
public function createOrderAction($paymentMethod) {
try {
$checkout_session = Mage::getSingleton('checkout/session');
$cq = $checkout_session->getQuote();
$cq->assignCustomer(Mage::getSingleton('customer/session')->getCustomer());
$quoteObj = Mage::getModel('sales/quote')->load($checkout_session->getQuoteId()); // Mage_Sales_Model_Quote
//Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()
$items = $quoteObj->getAllItems();
$quoteObj->reserveOrderId();
// set payment method
$quotePaymentObj = $quoteObj->getPayment(); // Mage_Sales_Model_Quote_Payment
$quotePaymentObj->setMethod($paymentMethod);
$quoteObj->setPayment($quotePaymentObj);
// convert quote to order
$convertQuoteObj = Mage::getSingleton('sales/convert_quote');
$quoteObj->setShippingAddress($cq->getShippingAddress());
$quoteObj->setBillingAddress($cq->getBillingAddress());
$orderObj = $convertQuoteObj->addressToOrder($quoteObj->getShippingAddress());
$orderPaymentObj = $convertQuoteObj->paymentToOrderPayment($quotePaymentObj);
// convert quote addresses
$orderObj->setBillingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getBillingAddress()));
$orderObj->setShippingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getShippingAddress()));
// set payment options
$orderObj->setPayment($convertQuoteObj->paymentToOrderPayment($quoteObj->getPayment()));
// convert quote items
foreach ($items as $item) {
// #var $item Mage_Sales_Model_Quote_Item
$orderItem = $convertQuoteObj->itemToOrderItem($item);
$orderItem->setWholesaler($item->getWholesaler());
$orderItem->setComment($item->getComment());
$options = array();
if ($productOptions = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct())) {
$options = $productOptions;
}
if ($addOptions = $item->getOptionByCode('additional_options')) {
$options['additional_options'] = unserialize($addOptions->getValue());
}
if ($options) {
$orderItem->setProductOptions($options);
}
if ($item->getParentItem()) {
$orderItem->setParentItem($orderObj->getItemByQuoteItemId($item->getParentItem()->getId()));
}
$orderObj->addItem($orderItem);
}
$orderObj->setCanShipPartiallyItem(false);
$orderObj->place();
$quoteObj->setIsActive(0)->save();
$orderObj->save();
$orderObj->sendNewOrderEmail();
return $orderObj->getId();
} catch (Exception $e){
Mage::log($e->getMessage());
Mage::log($e->getTraceAsString());
}
}

Categories