I want to add an item to my transaction.
$json = '
[
{
"name": "Voucher",
"description":"Voucher",
"price":"50.00",
"currency":"EUR",
"quantity":"1"
}
]';
$patchAddItem = new \PayPal\Api\Patch();
$patchAddItem->setOp('add')
->setPath('/transactions/0/item_list/items')
->setValue(json_decode($json));
$patchReplace = new \PayPal\Api\Patch();
$patchReplace->setOp('replace')
->setPath('/transactions/0/amount')
->setValue(json_decode('{
"total": "159.00",
"currency": "EUR",
}'));
$patchRequest = new \PayPal\Api\PatchRequest();
$patchRequest->setPatches(array($patchAddItem, $patchReplace));
try {
$this->payment->update($patchRequest, $this->apiContext);
} catch (PayPal\Exception\PayPalConnectionExceptio $ex) {
echo '<pre>';print_r(json_decode($ex->getData()));exit;
}
But I get following Error
Eception: Got Http response code 400 when accessing https://api.sandbox.paypal.com/v1/payments/payment/PAY... in PayPal-PHP-SDK/paypal/rest-api-sdk-php/lib/PayPal/Core/PayPalHttpConnection.php on line 154
PayPal-PHP-SDK/paypal/rest-api-sdk-php/lib/PayPal/Transport/PayPalRestCall.php on line 73: PayPal\Core\PayPalHttpConnection->execute("[{"op":"add","path":"/transactions/0/item_list/ite"... )
PayPal-PHP-SDK/paypal/rest-api-sdk-php/lib/PayPal/Common/PayPalResourceModel.php on line 102: PayPal\Transport\PayPalRestCall->execute(array[1],"/v1/payments/payment/PAY-1S151200BX2478240LEAG3CI","PATCH","[{"op":"add","path":"/transactions/0/item_list/ite"... ,null)
PayPal-PHP-SDK/paypal/rest-api-sdk-php/lib/PayPal/Api/Payment.php on line 615: PayPal\Common\PayPalResourceModel::executeCall("/v1/payments/payment/PAY-1S151200BX2478240LEAG3CI","PATCH","[{"op":"add","path":"/transactions/0/item_list/ite"... ,null,object,null)
At this moment I didn't execute the payment object. Do I have to edit the total attribut from amount too? Well, I tried this too, with same issue...
Even if you are sending only one item to PayPal you still have to set them as an item list with setItemList().
That array should be visible if you json_decode in your payment array:
[item_list] => Array
(
[items] => Array
(
[0] => Array
(
[name] => Ground Coffee 40 oz
[sku] => 123123
[price] => 52.80
[currency] => USD
[quantity] => 1
)
)
I had not run a patch for an item yet. I attempted to send an 'add' similar to your code and tried changing the path to '/transactions/0/item_list/items/1' using the next number in the items array. But could not get an add to work.
The only way I could modify the item_list was to do a complete 'replace' of the item_list, so in a running shopping cart would have to include all the items being purchased, not just the new item.
To do this I prefer to use the functions from the PayPal sdk vs building the json arrays. Their examples of how to create and execute a payment are fairly good and use the SDK functions. http://paypal.github.io/PayPal-PHP-SDK/sample/
However the example on updating a payments builds the json arrays outright.
Below is a testing function to modify the item_list using the Paypay PHP SDK Class Functions. I hard coded the Subtotal and Total to match the values coming form the shopping cart plus the increase from the new item. The item_list is also hard coded using PP's example data. Otherwise item's arrays would be built off of a user's shopping cart items. The type is set to 'replace'.
So, yes. Subtotals and Totals need to be updated to match as well, else the PP call will fail.
function updatePayPalPayment ($type, $createdPayment, $total, $subtotal, $shipping, $currency) {
$subtotal = '54.80';
$total = '71.73';
$details = new Details();
$details->setShipping($shipping)
->setSubtotal($subtotal);
$amount = new Amount();
$amount->setCurrency($currency)
->setTotal($total)
->setDetails($details);
$item1 = new Item();
$item1->setName('Ground Coffee 40 oz')
->setCurrency('USD')
->setQuantity(1)
->setSku("123123") // Similar to `item_number` in Classic API
->setPrice(52.80);
$item2 = new Item();
$item2->setName('Granola bars')
->setCurrency('USD')
->setQuantity(1)
->setSku("321321") // Similar to `item_number` in Classic API
->setPrice(2.0);
$itemList = new ItemList();
$itemList->setItems(array($item1, $item2));
$patchItem = new Patch();
$patchItem->setOp($type)
->setPath('/transactions/0/item_list')
->setValue($itemList);
$patchAmount = new Patch();
$patchAmount->setOp($type)
->setPath('/transactions/0/amount')
->setValue($amount);
$patchRequest = new PatchRequest();
$patchRequest->setPatches(array($patchAmount, $patchItem));
$update = $createdPayment->update($patchRequest, getApiContext());
return $update;
}
I also have found it very helpful to set the apiContext for logging to DEBUG and output to a file in development for much better error messages.
'log.LogEnabled' => true,
'log.FileName' => '_PayPal.log',
'log.LogLevel' => 'DEBUG',
Hope that helps.
Related
In my project, we have products that has tag called serviceItem. Those item with that tag when ordered should be separated by the quantity into individuals order.
It issue is that getTags() returns null, and getTagIds gets "Call to a member function getTagIds() on null" when it gets to the next loop.
Is there a reason for why getTags() returns null?
private function transformOrderLines(OrderEntity $order): array
{
/**
* TODO: If we need to send advanced prices,
* the price value of the the lines array should be changed to caldulate the advanced price,
* with the built in quantity calculator
*/
$lines = [];
foreach ($order->getLineItems() as $orderLine) {
$hasDsmServiceItemTag = $orderLine->getProduct()->getTags();
$lines[] = [
'name' => $orderLine->getLabel(),
'sku' => substr($orderLine->getProduct()->getProductNumber(), 0, 19),
'price' => (string) ($orderLine->getProduct()->getPrice()->first()->getNet()
* $order->getCurrencyFactor()), //gets original price, calculates factor
'quantity' => (string) $orderLine->getQuantity()
];
}
$shipping = $this->transformShipping($order);
if ($shipping) {
$lines = array_merge($lines, $shipping);
}
return $lines;
}`
I also tried $orderLine->getProduct()->getTags()->getName() it also return "Call to a member function getTags() on null"
The problem is wherever the $order is fetched from the DB the orderLineItem.product.tag association is not included in the criteria.
For performance reasons shopware does not lazily load all association when you access them on entities, but you have to exactly define which associations should be included when you fetch the entities from the database.
For the full explanation take a look at the docs.
I'm wondering if we are able to hook into WooCommerce to set a maximum amount of stock that can be purchased for a variable product. Disregarding the individual variation stock levels once this maximum amount is reached.
For example, I have a variable product selling workshop groups. There are 4 variations, each with a stock level set at 100. This is because no group can have more than 100 people in. However, only 250 tickets are available for sale (not 400 that we might expect because of the 4x100 quantity).
So this works as far as the max 100 places per workshop group. We just need to somehow be able to limit the total stock level of all 4 variations to 250.
I had hoped enabling the parent product "Manage stock" option and setting this to 250 would work. But obviously, variations must override this. If we can hook into that and turn that back on even when variation stock management is in use that might be a nice way of solving this.
Thanks for any help.
I came up with a solution to my problem by doing the following:
Add 2 custom fields to the WooCommerce product page, which will store the max quantity of the total variations we can sell and also the max quantity of an individual variation. The code for this is:
// Modify WooCommerce Product Settings
add_action('woocommerce_product_options_inventory_product_data', 'wc_add_custom_field' );
function wc_add_custom_field() {
$fields = array('Total quantity' => 'total_quantity','Variation quantity' => 'variation_quantity');
$field_description = array('total_quantity' ='description','variation_quantity' ='description');
$field_placeholder = array('total_quantity' =>'e.g. 300','variation_quantity' =>'e.g. 100');
foreach ($fields as $key => $value) {
woocommerce_wp_text_input( array(
'id' => $value,
'label' => $key,
'description' => $field_description[$value],
'desc_tip' => 'true',
'placeholder' => $field_placeholder[$value]
) );
}
}
// Save Fields
add_action( 'save_post_product', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
update_post_meta( $post_id, 'total_quantity', $_POST['total_quantity'] );
update_post_meta( $post_id, 'variation_quantity', $_POST['variation_quantity'] );
}
Add cart/basket validation rules to stop customers being able to purchase products that exceed the value of the custom "total_quantity" field added above:
add_action( "woocommerce_add_to_cart_validation","sc_woocommerce_add_to_cart_validation", 1, 5 );
function sc_woocommerce_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id, $variations ) {
// Iterate through each variation and get the total stock remaining
$product_variable = new WC_Product_Variable($product_id);
$product_variations = $product_variable->get_available_variations();
settype($variation_stock_availability, "integer");
foreach ($product_variations as $variation) {
$variation_stock_availability = +(int)$variation['max_qty'];
}
$count_variations = count($product_variations);
$total_quantity = get_post_meta( $product_id, 'total_quantity', true );
$variation_quantity = get_post_meta( $product_id, 'variation_quantity', true );
// formula to test if any stock remaining based on sold variations
$formula = $count_variations * $variation_quantity;
$formula1 = (int)$formula + (int)$quantity;
$formula1 = $formula1 - $variation_stock_availability;
// Iterating through each cart item and use the current running quantity in the cart in the forumula
foreach (WC()->cart->get_cart() as $cart_item_key=>$cart_item ){
// count(selected category) quantity
$running_qty += (int) $cart_item['quantity'];
$formula2 = (int)$formula + (int)$running_qty;
$formula2 = $formula2 - $variation_stock_availability;
// More than allowed products in the cart is not allowed
if ($formula2 >= $total_places) {
wc_add_notice( sprintf( __( "Unfortunately there is no availability based on your selection", "donaheys" )), 'error' );
$passed = false;
return $passed;
}
}
// More than allowed products in the cart is not allowed
if ($formula1 >= $total_places) {
// Add the error
wc_add_notice( sprintf( __( "Unfortunately there is no availability based on your selection", "donaheys" )), 'error' );
$passed = false;
return $passed;
} else {
$passed = true;
return $passed;
}
$running_qty = 0;
}
The result of the above code ensures we are can set a maximum amount of stock that can be purchased for a variable product, disregarding the individual variation stock levels once this maximum amount is reached.
I am integrating carrier service API for shopify store. I have partner account and also i have created development store. After installed my app in my store and subscribed carrier service. But in store shipping settings page i got an error
There are no available services for the countries you’ve selected
How to overcome this issue?
I have in the settings page:
My Carrier Service 5588680759
Rate adjustment: 0% + $0.00
There are no available services for the countries you’ve selected.
Automatically offering future shipping services when they become available
Screenshot:
how can i implement on Checkout Page?
I had the same problem and i solved it changing the callback url of the carrier service to public on my shopify application, you have to check if the url is accessible for everyone. (sorry for my english)
Shopify Documentation
You have to define Call url in shipment carries
"callback_url"=> base_url().'shipment/rates'
add these in controller or file which you add in call url
$filename = time();
$input = file_get_contents('php://input');
file_put_contents($filename.'-input', $input);
// parse the request
$rates = json_decode($input, true);
// log the array format for easier interpreting
file_put_contents($filename.'-debug', print_r($rates, true));
// total up the cart quantities for simple rate calculations
$quantity = 0;
foreach($rates['rate']['items'] as $item) {
$quantity =+ $item['quantity'];
}
// use number_format because shopify api expects the price to be "25.00" instead of just "25"
// overnight shipping is 5 per item
$overnight_cost = number_format(5, 2, '', '');
// overnight shipping is 1 to 2 days after today
$on_min_date = date('Y-m-d H:i:s O', strtotime('+1 day'));
$on_max_date = date('Y-m-d H:i:s O', strtotime('+2 days'));
// build the array of line items using the prior values
$output = array('rates' => array(
array(
'service_name' => 'Shipment Local',
'service_code' => 'SL',
'total_price' => $overnight_cost,
'currency' => 'PKR',
'min_delivery_date' => $on_min_date,
'max_delivery_date' => $on_max_date
)
));
// encode into a json response
$json_output = json_encode($output);
// log it so we can debug the response
file_put_contents($filename.'-output', $json_output);
// send it back to shopify
print $json_output;
Change According to you needs
I am trying to add product in Cart in Prestashop 1.6.7.
But it doesn't working.
Below is my code:
$context=Context::getContext();//new Cart();
$id_cart=$context->cookie->__get('id_cart');
$lan_id = $this->context->language->id;
$cur_id = $this->context->currency->id;
$products_ids=16571;
$cart=new Cart($id_cart);
$cart->id_currency=$cur_id;
$cart->id_lang=$lan_id;
$cart->updateQty(1,$products_ids, null, false);
But above code is not working.
Somehow i manage my code as per below:
global $context;
$context=Context::getContext();//new Cart();
$id_cart=$context->cookie->__get('id_cart');
$lan_id = $context->cookie->__get('id_lang');
$cur_id = $context->cookie->__get('id_currency');
$products_ids=16571;
$cart=new Cart($id_cart);
$cart->id_currency=$cur_id;
$cart->id_lang=$lan_id;
$this->context->cart->update();
$cart->updateQty(1,16571);
But there is one error for carrier
There are no carriers available that deliver to this address.
Try adding the following code at the end of your code.
$this->context->cart->save();
$this->context->cookie->id_cart = (int)$this->context->cart->id;
$this->context->cookie->write();
$this->context->cart->autosetProductAddress();
Hook::exec('actionAuthentication');
CartRule::autoRemoveFromCart($this->context);
CartRule::autoAddToCart($this->context);
I add some static Carrier ID in
classes/Cart.php
in getPackageList function at line no. approx. 1892
if (empty($product['carrier_list'])) {
$product['carrier_list'] = array(
'0' => 10,
'1' => 11
);
}
have an issue updating magento product from frontend using a module that its function is for customers to create their own products and have the admin approve before enabled(this part is working).
the problem is when a customer tries to updated their admin approved product (as before approval, product states that newly created product is pending, but they can still update the data/attributes created during the product create function, the same attributes that are not updating using the controller)
first of all i have a controller with the action to update the approved/pending customer product
public function editPostAction() {
$id = $this->getRequest()->getParam('productid');
if ( $id !== false ) {
list($data, $errors) = $this->validatePost();
if ( !empty($errors) ) {
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
$this->_redirect('customer/products/edit/', array(
'id' => $id
));
} else {
$customerId = $this->_getSession()->getCustomer()->getid();
$product = Mage::getResourceModel('customerpartner/customerpartner_product_collection')
->addAttributeToSelect('*')
->addAttributeToFilter('customer_id', $customerId)
->addAttributeToFilter('entity_id', $id)
->load()
->getFirstItem();
$product->setName($this->getRequest()->getParam('name'));
$product->setSku($this->getRequest()->getParam('sku'));
$product->setDescription($this->getRequest()->getParam('description'));
$product->setShortDescription($this->getRequest()->getParam('short_description'));
$product->setPrice($this->getRequest()->getParam('price'));
$product->setWeight($this->getRequest()->getParam('weight'));
$product->setStock($this->getRequest()->getParam('stock'));
$product->save();
if ( isset($_FILES) && count($_FILES) > 0 ) {
foreach($_FILES as $image ) {
if ( $image['tmp_name'] != '' ) {
if ( ( $error = $this->uploadImage($image, $id) ) !== true ) {
$errors[] = $error;
}
}
}
}
if ( empty($errors) ) {
$this->_getSession()->addSuccess($this->__('Your product was successfully updated'));
} else {
$this->_getSession()->addError('Product info was saved but was imposible to save the image');
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
}
$this->_redirect('customer/products/');
}
}
}
as well as a form that on submit is supposed to update the product attributes and images but the page reloads on submit and shows successful saved message but the attributes are not updated and going back to the edit form (for each product created) for that product the values in the update form have the values of the update we just submitted, bet yet the products attributes are not updated in the catalog either (they remain the same values as entered in the create new process)
don't no if to continue to figure out what is going wrong or just move to either use api or direct sql to get the job done.
see this post Magento 1.7: Non-system product attribute not saving in PHP script the problem maybe different but the solution can be found in that post
updated to a new action to call in .phtml see below as it seems to be updating the product data as needed, still wanting to improve..
called in form using /frontendname/editApprovedPost/
public function editApprovedPostAction() {
$id = $this->getRequest()->getParam('productid');
$idproduct = $this->getRequest()->getParam('product_id');
if ( $id !== false ) {
list($data, $errors) = $this->validatePost();
if ( !empty($errors) ) {
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
$this->_redirect('customer/products/edit/', array(
'id' => $id
));
} else {
- now added more php code to action (in this order) after the } else {...
require_once 'app/Mage.php';
then add admin store for frontend product updates...
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
then get the customer id...
$customerId = Mage::getSingleton('customer/session')->getCustomerId();
then use the forms product Id to get the Product Id to update...
$product = Mage::getModel('catalog/product')->load("".$idproduct."");
then use setName() to update/save the attribute value grabbed from the forms input value...
$product->setName($this->getRequest()->getParam('name'));//use whatever attributes need (only text and text area tested so far)
then save/update product data with...
$product->save();
then add to run through errors...
if ( empty($errors) ) {
$this->_getSession()->addSuccess($this->__('Your product was successfully updated'));
} else {
$this->_getSession()->addError('Product info was saved but was imposible to save the image');
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
}
$this->_redirect('customer/products/');
}
}
}
then with a form to submit in frontend with customer logged in and customer group config
custom form only visible to Customer Group 2 (default is Wholesale)
form below....
sorry cant paste form to much work to paste the code here, any way using the
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
which i have read in some posts is that to update product in frontend you need to be "admin", which this seems to do just fine. As Noted before, the script was not updating and it was because it is trying to save to a different models data when the data to be updated was an actual product (that has been approved and created using the different models data) and it was updating using
$product = Mage::getResourceModel('customerpartner/customerpartner_product_collection')
would be good to here anyone else's comments
hope this helps someone because was think time to close this build.