I manually manage my stocks on Prestashop. I am looking for a solution to automatically return the initial stock after a sales order.
For example, a product is ordered in two copies with an initial stock of 7. I would like the stock to remain at 7 after the order and not at 5.
Do you know a technique that would allow me to realize this automatically?
Put a Hook on Order Confirmation (displayOrderConfirmation) in a new module (you can generate one at https://validator.prestashop.com/) and check whats inside the cart then put it again in your stocks :
public function hookDisplayOrderConfirmation($params) {
$order = $params['order'];
$cart = new Cart($order->id_cart);
$products = $cart->getProducts();
foreach ($products as $product) {
$removed_qty = (int) $product['quantity'];
$past_qty = (int) StockAvailable::getQuantityAvailableByProduct($product['id_product'], $product['id_product_attribute']);
$new_qty = $removed_qty + $past_qty;
StockAvailable::setQuantity($product['id_product'], $product['id_product_attribute'], $new_qty);
}
}
Related
I use multi-store option with prestashop. I would like to pass customers in the second store to manual activation after registration.
Actually I set $customer->active = 0; in authentication.php.
all registration customer in both websites are inactive after registration.
Is there a way to set $customer->active = 0; just for one website.
I think to get shop_id but I don't know how to develop my idea.
In Prestashop 1.6 :
You can get the id_shop with the Context object.
So, I think you can do something like this :
If you know the id_shop (suppose the id_shop = 1)
if (Context::getContext()->shop->id == 1) {
$customer->active = 0;
} else {
$customer->active = 1;
}
Hope it helps.
EDIT
Updated answer to get the id_shop from context because the Customer object doesn't handle it until it's added.
RE-EDIT
In the Customer class (/classes/Customer.php) customize the add() function.
Add this line around the line 212 (after the "last_passwd_gen" declaration) :
$this->active = ($this->id_shop == 3) ? false : true;
But the best solution for you is to create an override of the function.
i have an add product function and it registers well in my database. it looks like this
after that, customer orders and what i have currently is that it only updates the label (available stock) not in the database. here is my code for that after button click:
DataTable dtResult = k.SaveCustomerDetails();
for (int i = 0; i < dt.Rows.Count; i++) // loop on how many products are added by the user
{
ShoppingCart SaveProducts = new ShoppingCart()
{
CustomerID = Convert.ToInt32(dtResult.Rows[0][0]),
ProductID = Convert.ToInt32(dt.Rows[i]["ProductID"]),
TotalProducts = Convert.ToInt32(dt.Rows[i]["ProductQuantity"]), //subtracts the product quantity depending
//on the customer order
};
SaveProducts.SaveCustomerProducts();
}
var customerId = Convert.ToInt32(dtResult.Rows[0][0]);
Response.Redirect(String.Format("OrderSummary.aspx?Id={0}", customerId.ToString()));
what I want to happen is to update the product quantity as well in the database? any idea on how to do it? please and thank you sirs
I want to create a Script in NetSuite which needs some history information from a customer. In fact the information I need is to know if the user has purchased an item.
For this, I would need in some way to access to the history of this customer.
Pablo.
Try including this function and passing customer's internalID and item internalID
function hasPurchasedBefore(customerInternalID, itemInternalID){
var results = [];
var filters = [];
var columns = [];
filters.push(new nlobjSearchFilter('internalidnumber', 'customermain', 'equalto', [customerInternalID]))
filters.push(new nlobjSearchFilter('anylineitem', null, 'anyof', [itemInternalID]));
filters.push(new nlobjSearchFilter('type', null, 'anyof', ['CustInvc']));
columns.push(new nlobjSearchColumn('internalid', null, 'GROUP'));
results = nlapiSearchRecord('transaction', null, filters, columns);
if (results && results.length){
return true;
}
return false;
}
Example:
var record = nlapiLoadRecord(nlapiGetRecordType(),nlapiGetRecordId());
var customerInternalID = record.getFieldValue('entity');
var itemInternalID = record.getLineItemValue('item', 'item', 1); //Gets line 1 item Internal ID
if( hasPurchasedBefore(customerInternalID, itemInternalID) ) {
//Has bought something before
}
You could use a saved search nlapiLoadSearch or nlapiCreateSearch for invoices, filtered by customer, and also reporting invoice items (or just a particular item). Using nlapiCreateSearch can be tricky to use, so I'd recommend building the saved search using the UI, then load it using nlapiLoadSeach(type, id)
This will give you an array of invoices/customers that bought your item.
Has anyone tried to create a plugin that updates the record's values in the Quote Product form? I created one, because I need a custom formula that calculates the Extended Amount field, but there are automatic calculations in the CRM that fill these fields. This doesn't allow me to update the formula of calculation at all.
What my plugin do, is:
Gets the values from the fields Price per unit, Quantity and Discount % (which is a custom field);
Calculates the value that I need;
Sets it at the extended amount field.
But, none of this works because I get a "Business Process Error";
Basically this error tells me that I can't use the record's guid to access it.
Here is my code:
protected void ExecutePostQuoteProductUpdate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
Guid quoteProductID = (Guid)((Entity)context.InputParameters["Target"]).Id;
ColumnSet set = new ColumnSet();
set.AllColumns = true;
var quote = service.Retrieve("quotedetail", quoteProductID, set);
var priceperunit = quote.Attributes["priceperunit"];
var teamleader = quote.Attributes["new_disc"];
var manualdiscountamount = quote.Attributes["manualdiscountamount"];
var volumediscountamount = quote.Attributes["volumediscountamount"];
var VAT = (int)quote.Attributes["new_vat"];
var discountamount = (double)priceperunit * (double)teamleader / 100;
var baseamount = (double)priceperunit - discountamount;
var tax = baseamount * VAT / 100;
var extendedamount = baseamount + tax;
quote.Attributes["new_discountamount"] = discountamount;
quote.Attributes["baseamount"] = baseamount;
quote.Attributes["tax"] = tax;
quote["description"] = priceperunit;
quote.Attributes["extendedamount"] = extendedamount;
service.Update(quote);
}
Please, tell me if there is a way to access those fields and use/set them.
Thanks in Advance!
:/
You cannot update extendedamount directly - instead if you use the built-in fields which automatically calculate it then CRM will take care of this for you.
Those fields are: baseamount, quantity, discountamount, and tax. These are Money fields so you will need to store them as such:
quote.Attributes["baseamount"] = new Money(baseamount); // Money and decimal numbers use the "decimal" datatype and not double.
As for your custom calculation, you just need to convert the percentage stored in your custom field into the actual amount and assign it to the discountamount attribute. Something like:
var discountamount = (decimal)priceperunit * (decimal)teamleader / 100;
// Assigning the actual discount amount will automatically recalculate the extended amount on the line.
// No need to recalculate all fields.
quote.Attributes["discountamount"] = new Money(discountamount);
Note that tax may need to be recalculated to reflect the discount, but the process should work exactly the same.
We've got some API integrations that will periodically create shipments for orders.
What I'd like to do is create an observer to also create an appropriate invoice & capture payment when this shipment is created. I have this tied to sales_order_shipment_save_after:
public function autoInvoice($observer){
$shipment = $observer->getEvent()->getShipment();
$order = $shipment->getOrder();
$items = $shipment->getItemsCollection();
$qty = array();
foreach($items as $item)
$qty[$item['order_item_id']] = $item['qty'];
$invoice = Mage::getModel('sales/order_invoice_api');
$invoiceId = $invoice->create($order->getIncrementId(), $qty);
$invoice->capture($invoiceId);
}
(The code for the actual capture is somewhat naive, but bear with me.)
What's strange is that this code works just fine -- the shipment is created, the invoice is created and marked as 'Paid.' However, the order itself stays in limbo and retains a status 'Pending.'
Looking into it further, the items on the order itself have the correct quantities for both Ordered and Shipped, but there's no listing of the quantity Invoiced. I think this is what's causing the status hangup. It's as though the qty_invoiced on the sales_order_item table is getting reverted somehow.
Again, the Invoice shows the right items, so I'm quite confused here.
Any ideas?
This is indeed a very interesting one #bahoo.
maybe try:
$shipment = $observer->getEvent()->getShipment();
$order = $shipment->getOrder();
$qty = array();
$invoice = Mage::getModel('sales/order_invoice_api');
$invoiceId = $invoice->create($order->getIncrementId(), $qty);
$invoice->capture($invoiceId);
After lots of testing using the API, I found if I created the invoice first, then the shipment, Magento Enterprise 1.13.01. would correctly set the order status to Complete. Trying to make the shipment first, then the invoice, would result in the Pending Order status remaining even if all items had been invoiced and shipped.
The bridging system code below uses information about orders placed in Magento, routed to the bridging system via an Observer on checkout_submit_all_after, sent to NetSuite via web services, and fulfilled in NetSuite. The bridging system gets sales order fulfillments from NetSuite via web service, and saves items shipped, package, and tracking information, to use in the code below.
Code shows creating invoice, then shipment and tracking.
Note that while testing, I just saw Magento incorrectly create an invoice for all three items in an order, even though it was passed an array that just contained two of the items. Magento did correctly create a shipment record for just the two items. Puzzling that the invoice API and the shipment API when passed the same array of items and quantities have such different behavior. Anyone else seen this?
$proxy = new SoapClient($proxyUrl); /* V2 version */
$sessionId = $proxy->login($apiUser, $apiKey);
try
{ /* try to create invoice in Magento */
$invoiceIncrementId = $proxy->salesOrderInvoiceCreate($sessionId, $orderIncrementId, $shipItemsQty, 'invoice created', false, false);
}
catch( SoapFault $fault )
{
$error = $fault->getMessage(); /* will return 'Cannot do invoice for order' if invoice already exists for these items */
}
if (!stristr($error,'Cannot do invoice') and !empty($error))
{ /* some other invoicing problem, log what returned, on to next order */
$ins = "insert into order_error_log values(NULL, ".$orderId.", '".date("Y-m-d H:i:s")."', '".$program."', '".$error."')";
$result = $mysqli->query($ins);
$upd = "update orders set orderStatusId = ".ERROR_ADDING_MAGENTO_INVOICE.",
dateStatusUpdated = '".date("Y-m-d H:i:s")."'
where id = ".$orderId;
$result = $mysqli->query($upd);
continue;
}
if ((stristr($error,'Cannot do invoice') or empty($error)) and $complete)
{ /* if all fulfilled, may change status */
$upd = "update orders set orderStatusId = ".STORE_INVOICE_CREATED.",
dateStatusUpdated = '".date("Y-m-d H:i:s")."'
where id = ".$orderId;
$result = $mysqli->query($upd);
}
/* send Magento salesOrderShipmentCreate and get returned shipment Id, re-using proxy login and session */
$comment = 'Fulfillment(s) shipped on: '.$netsuiteShipDate;
try
{ /* returns value such as string(9) "100002515" */
$shipmentIncrementId = $proxy->salesOrderShipmentCreate($sessionId, $orderIncrementId, $shipItemsQty, $comment);
}
catch( SoapFault $fault )
{
$error = $fault->getMessage().': SOAP error received when trying to add shipment to Magento for morocco order id '.$orderId.
' store order id '.$orderIncrementId.' with items qty array of: '.var_dump($itemsQty);
$ins = "insert into order_error_log values(NULL, ".$orderId.", '".date("Y-m-d H:i:s")."', '".$program."', '".$error."')";
$result = $mysqli->query($ins);
$upd = "update orders set orderStatusId = ".MAGENTO_SOAP_EXCEPTION.",
dateStatusUpdated = '".date("Y-m-d H:i:s")."'
where id = ".$orderId;
$result = $mysqli->query($upd);
continue; /* on to next order */
}
/* Using that shipmentId, send info re each package shipped for these fulfillments to Magento via salesOrderShipmentAddTrack. */
foreach ($packageIds as $packageId => $package)
{
try
{
$trackingNumberId = $proxy->salesOrderShipmentAddTrack($sessionId, $shipmentIncrementId,
$package['carrier'], 'tracking number', $package['trackNumber']);
}
catch( SoapFault $fault )
{
$error = $fault->getMessage().': SOAP error received when trying to add tracking number '.$package['trackNumber'].' to
Magento for morocco order id '.$orderId.' store order id '.$orderIncrementId;;
$ins = "insert into order_error_log values(NULL, ".$orderId.", '".date("Y-m-d H:i:s")."', '".$program."', '".$error."')";
$result = $mysqli->query($ins);
$upd = "update orders set orderStatusId = ".MAGENTO_SOAP_EXCEPTION.",
dateStatusUpdated = '".date("Y-m-d H:i:s")."'
where id = ".$orderId;
$result = $mysqli->query($upd);
continue;
}
}