payment module in prestashop 1.6.1.x doesn't send total price with shipment - prestashop

In my Prestashop store, I have a payment module that sends the total amount to an external API:
/** CART ITEMS */
$products = $cart->getProducts();
$CartItems = [];
$api_currency_id = (int)Currency::getIdByIsoCode($currency_iso);
foreach($products as $product) {
if ($this->context->currency->id != $api_currency_id) {
$price = Tools::convertPrice((float)$product['price_wt'], $this->context->currency, false);
$price = Tools::convertPrice((float)$price, $api_currency_id);
} else {
$price = (float)$product['price_wt'];
}
$CartItem['Amount'] = Tools::ps_round($price) ;
$CartItem['Currency'] = $currency_iso;
$CartItem['Name'] = $product['name'];
$CartItem['Description'] = strip_tags($product['description_short']);
$CartItem['Quantity'] = (int)$product['cart_quantity'];
$CartItem['IsTaxFree'] = $product['price'] != $product['price_wt'];
The problem is when the purchase includes the shipping price, the amount that sends to the API is without the shipping .
what do I need to fix in the code, so that the $CartItem['Amount'] will include the shipping cost?

The shipping price is a different amount. With a proper flag, you can get all the prices you need using Cart::getOrderTotal(). For instance:
$cart->getOrderTotal(true, Cart::ONLY_SHIPPING)
It will return you the amount of shipping for a given shopping cart.

Related

Max shipping cost

How do I set the maximum shipment amount per 199 in PrestaShop 1.7?
It may be smaller, but it may not exceed 199.
In which file do I look for the variable corresponding to the amount of the shipment?
Override function getPackageShippingCost() from Cart class:
class Cart extends CartCore
{
public function getPackageShippingCost($id_carrier = null, $use_tax = true, Country $default_country = null, $product_list = null, $id_zone = null)
{
$shipping_cost = parent::getPackageShippingCost($id_carrier, $use_tax, $default_country, $product_list, $id_zone);
if ($shipping_cost > 199) {
return 199;
}
}
}
Remember to remove class_index.php and clear cache.

Prestashop 1.7 check available stock at final order step

I had something working on Prestashop 1.6 to check cart quantities before the customer can buy. Here is my problem on Prestashop 1.7 :
If a customer put an item in his cart today, he comes back in 2 days and he is still logged in. The cart is still available while the product, in reality, became out of stock.
The customer can make the order and the quantity in my stock is -1. Since I upgraded to prestashop 1.7 it's a disaster, I have quantities at -5, -10...because if this non-checked scenario.
abstract class PaymentModule extends PaymentModuleCore
{
public function validateOrder($id_cart, $id_order_state, $amount_paid, $payment_method = 'Unknown',
$message = null, $extra_vars = array(), $currency_special = null, $dont_touch_amount = false,
$secure_key = false, Shop $shop = null)
{
if (!isset($this->context))
$this->context = Context::getContext();
$this->context->cart = new Cart($id_cart);
if (!$this->context->cart->checkQuantities()){
Tools::redirect(__PS_BASE_URI__.'order.php?step=0');
}
return parent::validateOrder($id_cart, $id_order_state, $amount_paid, $payment_method, $message,
$extra_vars, $currency_special, $dont_touch_amount, $secure_key, $shop);
}
}
Actually the best solution is to use this addons : https://addons.prestashop.com/en/stock-supplier-management/21707-temporary-product-reservation-lonely-stock.html
Prestashop handles really bad cart stocks.
Anyway if you want to do it yourself and check stock available it's pretty simple :
<?php
$cart = $this->context->cart;
$cart_products = $cart->getProducts();
if (!empty($cart_products)) {
$db = Db::getInstance();
foreach ($cart_products as $key => $cart_product) {
$real_quantity = StockAvailable::getQuantityAvailableByProduct($cart_product['id_product'], $cart_product['id_product_attribute']);
if ( (int) $real_quantity < (int) $cart_product['quantity'] ) {
// If negative
$real_quantity = (int) $real_quantity < 0 ? 0 : $real_quantity;
$sql = '
UPDATE `'._DB_PREFIX_.'cart_product`
SET quantity = '.(int) $real_quantity.',`date_add` = NOW()
WHERE `id_product` = '.(int) $cart_product['id_product'].
(!empty($cart_product['id_product_attribute']) ? ' AND `id_product_attribute` = '.(int) $cart_product['id_product_attribute'] : '').'
AND `id_cart` = '.(int) $cart->id;
$db->execute($sql);
}
}
// Garbage collector
$db->execute('DELETE FROM '._DB_PREFIX_.'cart_product WHERE quantity < 1 ');
}

Getting "Received unknown parameter: amounts" for bank Account "Verify" function for jaymedavis/stripe.net code.?

I am implementing WCF service to implement online Net banking using github jaymedavis/stripe.net code (https://github.com/jaymedavis/stripe.net#charges).
here is my code for creating customer, Bank Account and Bank Account service for verifying Bank account and Creating charges.
Code:
//1. Create Customer
var myCustomer = new StripeCustomerCreateOptions();
myCustomer.Email = "pork#email.com";
myCustomer.Description = "Johnny Tenderloin (pork#email.com)";
//myCustomer.SourceToken = *token*;
//myCustomer.PlanId = *planId*; // only if you have a plan
//myCustomer.TaxPercent = 20; // only if you are passing a plan, this tax percent will be added to the price.
//myCustomer.Coupon = *couponId*; // only if you have a coupon
//myCustomer.TrialEnd = DateTime.UtcNow.AddMonths(1); // when the customers trial ends (overrides the plan if applicable)
//myCustomer.Quantity = 1; // optional, defaults to 1
//2. Create Customer Service
var customerService = new StripeCustomerService(StripeApiKey);
StripeCustomer stripeCustomer = customerService.Create(myCustomer);
//3. Create bankAccount
var myBankAccount = new BankAccountCreateOptions
{
SourceBankAccount = new SourceBankAccount()
{
AccountNumber = "000123456789", //,
Country = "US",
Currency = "usd",
AccountHolderName = "Frank", //"Johnny Tenderloin",
AccountHolderType = BankAccountHolderType.Individual,
RoutingNumber = "110000000", //"021000021",
Metadata = new Dictionary<string, string>
{
{ "Name", "Ray Barone" },
{ "OftenSays", "Thatttttt's right" }
}
}
};
//4. Create bankAccount Service
var bankAccountService = new BankAccountService(StripeApiKey);
CustomerBankAccount bankAccount = bankAccountService.Create(stripeCustomer.Id, myBankAccount);
BankAccountVerifyOptions bankAccountVerifyOpt = new BankAccountVerifyOptions();
bankAccountVerifyOpt.AmountOne = 32;
bankAccountVerifyOpt.AmountTwo = 45;
//
//5. Verify bankAccount or service
bankAccount = bankAccountService.Verify(stripeCustomer.Id, bankAccount.Id, bankAccountVerifyOpt );
//6. Create Charge
var myChargeBank = new StripeChargeCreateOptions();
// amount = Returnamount.amount;
myChargeBank.Amount = int.Parse("250") * 100;
myChargeBank.Currency = "usd";
myChargeBank.CustomerId = stripeCustomer.Id;
myChargeBank.Capture = true;
StripeCharge stripeCharge = null;
stripeCharge = new StripeCharge();
var chargeService = new StripeChargeService(StripeApiKey);
stripeCharge = chargeService.Create(myChargeBank);
if (stripeCharge.Status.ToLower() == "succeeded" & stripeCharge.Paid == true) {
} else {
}
In this code, I am getting:
Stripe Exception for Verify method (bankAccountService.Verify(stripeCustomer.Id, bankAccount.Id, bankAccountVerifyOpt );)
Exception is Received unknown parameter: amounts.
on "https://github.com/jaymedavis/stripe.net#charges" implementation for 'Verify a bank account' is missing so Please help me to solve this problem so that bank account get verify successfully.
I had the same issue and I did 2 things:
1) On stripe.com, I went to my account API settings and updated them to use the lasted API.
2) I updated the Stripe.net Nuget package
After that everything worked perfectly.

Creating/Retrieving a Cart programmatically

For a module that I'm writing I need to retrieve a cart for a certain user (not necessary registered) after that a link is called and some data are passed.
My idea was to receive back a previously id passed that can help me to identify a certain cart.
My big problem is that I've search a lot for code cart creation into prestashop. Finally I've found something into
/* Cart already exists */
if ((int)$this->context->cookie->id_cart)
{
$cart = new Cart($this->context->cookie->id_cart);
if ($cart->OrderExists())
{
unset($this->context->cookie->id_cart, $cart, $this->context->cookie->checkedTOS);
$this->context->cookie->check_cgv = false;
}
/* Delete product of cart, if user can't make an order from his country */
elseif (intval(Configuration::get('PS_GEOLOCATION_ENABLED')) &&
!in_array(strtoupper($this->context->cookie->iso_code_country), explode(';', Configuration::get('PS_ALLOWED_COUNTRIES'))) &&
$cart->nbProducts() && intval(Configuration::get('PS_GEOLOCATION_NA_BEHAVIOR')) != -1 &&
!FrontController::isInWhitelistForGeolocation() &&
!in_array($_SERVER['SERVER_NAME'], array('localhost', '127.0.0.1')))
unset($this->context->cookie->id_cart, $cart);
// update cart values
elseif ($this->context->cookie->id_customer != $cart->id_customer || $this->context->cookie->id_lang != $cart->id_lang || $currency->id != $cart->id_currency)
{
if ($this->context->cookie->id_customer)
$cart->id_customer = (int)($this->context->cookie->id_customer);
$cart->id_lang = (int)($this->context->cookie->id_lang);
$cart->id_currency = (int)$currency->id;
$cart->update();
}
/* Select an address if not set */
if (isset($cart) && (!isset($cart->id_address_delivery) || $cart->id_address_delivery == 0 ||
!isset($cart->id_address_invoice) || $cart->id_address_invoice == 0) && $this->context->cookie->id_customer)
{
$to_update = false;
if (!isset($cart->id_address_delivery) || $cart->id_address_delivery == 0)
{
$to_update = true;
$cart->id_address_delivery = (int)Address::getFirstCustomerAddressId($cart->id_customer);
}
if (!isset($cart->id_address_invoice) || $cart->id_address_invoice == 0)
{
$to_update = true;
$cart->id_address_invoice = (int)Address::getFirstCustomerAddressId($cart->id_customer);
}
if ($to_update)
$cart->update();
}
}
if (!isset($cart) || !$cart->id)
{
$cart = new Cart();
$cart->id_lang = (int)($this->context->cookie->id_lang);
$cart->id_currency = (int)($this->context->cookie->id_currency);
$cart->id_guest = (int)($this->context->cookie->id_guest);
$cart->id_shop_group = (int)$this->context->shop->id_shop_group;
$cart->id_shop = $this->context->shop->id;
if ($this->context->cookie->id_customer)
{
$cart->id_customer = (int)($this->context->cookie->id_customer);
$cart->id_address_delivery = (int)(Address::getFirstCustomerAddressId($cart->id_customer));
$cart->id_address_invoice = $cart->id_address_delivery;
}
else
{
$cart->id_address_delivery = 0;
$cart->id_address_invoice = 0;
}
// Needed if the merchant want to give a free product to every visitors
$this->context->cart = $cart;
CartRule::autoAddToCart($this->context);
}
that is contained into FrontController.php (that seems to be called in every page). So, to me, a cart should always be present during a "user session".
But - yes, there's a but - when I try to retrieve a cart (in that way, into controller of my module)
$context=Context::getContext();
$id_cart=$context->cart->id;
$id_cart isn't there, so cart seems to miss. So I'm a little bit confused.
What's goin' on here? Someone could give me some pointers?
PS.:
I've tried to replicate that function (only the else part) but it doesn't work
You can force cart generation when the user isn't logged in and there is no product in the cart:
$context = Context::getContext();
if (!$context->cart->id) {
$context->cart->add();
$context->cookie->id_cart = $context->cart->id;
}
$id_cart = $context->cart->id;
Take a look at the processChangeProductInCart method in controllers/front/CartController.php
I'm using Prestashop 1.6, and #yenshiraks answer did not work for me. I cannot use $context->cart->add();, because $context->cartis null.
This is what worked in my case:
$context = Context::getContext();
$cart_id = null
if($context->cookie->id_cart) {
$cart = new Cart($context->cookie->id_cart);
$cart_id = $cart->id; // just in case the cookie contains an invalid cart_id
}
if(empty($cart_id)) {
$cart = new Cart();
$cart->id_lang = (int)$context->cookie->id_lang;
$cart->id_currency = (int)$context->cookie->id_currency;
$cart->id_guest = (int)$context->cookie->id_guest;
$cart->id_shop_group = (int)$context->shop->id_shop_group;
$cart->id_shop = $context->shop->id;
$cart->add();
$cart_id = $cart->id;
}
$context->cookie->id_cart = $cart_id;
To answer the question at the end: Even though a cart is always generated in the FrontController, it is not saved to the database, therefore the id is null.
If you are in a context, where the FrontController is instantiated (any page of the frontend, $context->cart->add(); will suffice to save an empty cart to the database.
If on the other hand, you are in a script, that is called directly (like prestashop/modules/my_module/script.php), you have to use the above code.

When is a groupby query evaluated in RavenDB?

I'm struggling with the behaviour of grouping using RavenDB and LuceneQuery.
I was always under the impression that IEnumerable was only evaluated when calling ToArray(), etc.
The following query was split into two parts for the sake of clarity.
I would not expect the query to be evaluated until after ToArray() is called on totalledBalanceList, my expectation being that the grouping is done on the server across all of the data. However, the actual result depends on the number of items stipulated in .Take(). Without the Take(1024), the results come back for the default 128 items.
I need to be able to perform the grouping across the entire dataset.
using (var session = MvcApplication.RavenSession)
{
var computedBalanceList =
from c in session.Advanced.LuceneQuery<Journal, Ledger_ByDateAndDebitIdAndCreditIdAndValues>()
.Where(parameters)
.OrderBy(c => c.DateAsString).Take(1024)
select new LedgerBalanceDto
{
Account = account,
Name = queryName,
Debits = c.DebitId == account.Id
? c.DebitValue
: 0,
Credits = (c.CreditId == account.Id)
? c.CreditValue
: 0,
Currency = (c.DebitId == account.Id) ? c.DebitCurrency : c.CreditCurrency,
CurrencySymbol = (c.DebitId == account.Id) ? c.DebitCurrencySymbol : c.CreditCurrencySymbol,
};
var totalledBalanceList =
from balance in computedBalanceList
group new {balance.Debits, balance.Credits} by new {balance.Currency, balance.CurrencySymbol}
into grouping
select new LedgerBalanceDto
{
Account = account,
Currency = grouping.Key.Currency,
CurrencySymbol = grouping.Key.CurrencySymbol,
Debits = grouping.Sum(c => c.Debits),
Credits = grouping.Sum(c => c.Credits),
Name = queryName
};
return totalledBalanceList;
And the index:
public class Ledger_ByDateAndDebitIdAndCreditIdAndValues:AbstractIndexCreationTask<Journal>
{
public Ledger_ByDateAndDebitIdAndCreditIdAndValues()
{
Map = journals => from c in journals
select new {c.Date,c.DateAsString, c.DebitId, c.CreditId,c.DebitValue,c.CreditValue};
Index(x=>x.Date,FieldIndexing.Analyzed);
Index(x=>x.DateAsString,FieldIndexing.Analyzed);
Index(x=>x.DebitId,FieldIndexing.Analyzed);
Index(x=>x.CreditId,FieldIndexing.Analyzed);
Index(x=>x.DebitValue,FieldIndexing.Analyzed);
Index(x=>x.CreditValue,FieldIndexing.Analyzed);
Sort(x=>x.DateAsString,SortOptions.String);
}
}
I've also rewritten the query so that the grouping happens "outside" the filter, but I get exactly the same results, namely the result depends on the Take().
var totalledBalanceList = from balance in
from c in query
.Where(parameters)
.OrderBy(c => c.DateAsString)
select new LedgerBalanceDto
{
Account = account,
Name = queryName,
Debits = c.DebitId == account.Id
? c.DebitValue
: 0,
Credits = (c.CreditId == account.Id)
? c.CreditValue
: 0,
Currency = (c.DebitId == account.Id) ? c.DebitCurrency : c.CreditCurrency,
CurrencySymbol = (c.DebitId == account.Id) ? c.DebitCurrencySymbol : c.CreditCurrencySymbol,
}
group new {balance.Debits, balance.Credits} by new {balance.Currency, balance.CurrencySymbol}
into grouping
select new LedgerBalanceDto
{
Account = account,
Currency = grouping.Key.Currency,
CurrencySymbol = grouping.Key.CurrencySymbol,
Debits = grouping.Sum(c => c.Debits),
Credits = grouping.Sum(c => c.Credits),
Name = queryName
};
return totalledBalanceList;
Any thoughts on this would be much appreciated.
Part of the Journal class:
public class Journal
{
public string Id { get; set; }
public string DebitId{get;set;}
public string CreditId{get;set;}
public decimal? ExchangeRate { get; set; }
public decimal CreditValue {get;set;}
public decimal DebitValue {get;set;}
public string DebitCurrency {get;set;}
public string CreditCurrency {get;set;}
public decimal Nett
{
get { return _nett; }
set
{
_nett = value;
CreditValue = Math.Round(Nett, 2);
DebitValue = Math.Round(Nett * (ExchangeRate ?? 1), 2);
}
}
etc ...
}
Example data IEnumerable<Journal>:
Id DebitId CreditId Nett ExchangeRate DbCurr CrCurr DbVal CrVal
1 Expense1 Bank 100 2.03 BRL USD 203.00 100.00
2 Expense2 Bank 50 null USD USD 50.00 50.00
3 Bank Client1 300 null USD USD 300.00 300.00
4 Stock Bank 300 null USD USD 300.00 300.00
For example, when I query for the Bank, I want to be able to sum the DbVal and CrVal and calculate the balance, but in order to do so, I have to zero either one or the other (as per the query).
You are mixing LINQ and Lucene query here, and that means they will be evaluated on the client.
You need to move a lot of this into an index and query that using session.Query, not session.Advanced.LuceneQuery.