Initial commit

This commit is contained in:
2020-10-07 10:37:15 +02:00
commit ce5f440392
28157 changed files with 4429172 additions and 0 deletions

2687
classes/order/Order.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderCarrierCore extends ObjectModel
{
/** @var int */
public $id_order_carrier;
/** @var int */
public $id_order;
/** @var int */
public $id_carrier;
/** @var int */
public $id_order_invoice;
/** @var float */
public $weight;
/** @var float */
public $shipping_cost_tax_excl;
/** @var float */
public $shipping_cost_tax_incl;
/** @var string */
public $tracking_number;
/** @var string Object creation date */
public $date_add;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_carrier',
'primary' => 'id_order_carrier',
'fields' => array(
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_carrier' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_order_invoice' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'weight' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'shipping_cost_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'shipping_cost_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'tracking_number' => array('type' => self::TYPE_STRING, 'validate' => 'isTrackingNumber'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
protected $webserviceParameters = array(
'objectMethods' => array('update' => 'updateWs'),
'fields' => array(
'id_order' => array('xlink_resource' => 'orders'),
'id_carrier' => array('xlink_resource' => 'carriers'),
),
);
/**
* @param Order $order Required
*
* @return bool
*/
public function sendInTransitEmail($order)
{
$customer = new Customer((int) $order->id_customer);
$carrier = new Carrier((int) $order->id_carrier, $order->id_lang);
$address = new Address((int) $order->id_address_delivery);
if (!Validate::isLoadedObject($customer)) {
throw new PrestaShopException('Can\'t load Customer object');
}
if (!Validate::isLoadedObject($carrier)) {
throw new PrestaShopException('Can\'t load Carrier object');
}
if (!Validate::isLoadedObject($address)) {
throw new PrestaShopException('Can\'t load Address object');
}
$products = $order->getCartProducts();
$link = Context::getContext()->link;
$metadata = '';
foreach ($products as $product) {
$prod_obj = new Product((int) $product['product_id']);
//try to get the first image for the purchased combination
$img = $prod_obj->getCombinationImages($order->id_lang);
$link_rewrite = $prod_obj->link_rewrite[$order->id_lang];
$combination_img = $img[$product['product_attribute_id']][0]['id_image'];
if ($combination_img != null) {
$img_url = $link->getImageLink($link_rewrite, $combination_img, 'large_default');
} else {
//if there is no combination image, then get the product cover instead
$img = $prod_obj->getCover($prod_obj->id);
$img_url = $link->getImageLink($link_rewrite, $img['id_image']);
}
$prod_url = $prod_obj->getLink();
$metadata .= "\n" . '<div itemprop="itemShipped" itemscope itemtype="http://schema.org/Product">';
$metadata .= "\n" . ' <meta itemprop="name" content="' . htmlspecialchars($product['product_name']) . '"/>';
$metadata .= "\n" . ' <link itemprop="image" href="' . $img_url . '"/>';
$metadata .= "\n" . ' <link itemprop="url" href="' . $prod_url . '"/>';
$metadata .= "\n" . '</div>';
}
$orderLanguage = new Language((int) $order->id_lang);
$templateVars = array(
'{followup}' => str_replace('@', $this->tracking_number, $carrier->url),
'{firstname}' => $customer->firstname,
'{lastname}' => $customer->lastname,
'{id_order}' => $order->id,
'{shipping_number}' => $this->tracking_number,
'{order_name}' => $order->getUniqReference(),
'{carrier}' => $carrier->name,
'{address1}' => $address->address1,
'{country}' => $address->country,
'{postcode}' => $address->postcode,
'{city}' => $address->city,
'{meta_products}' => $metadata,
);
if (@Mail::Send(
(int) $order->id_lang,
'in_transit',
$this->trans(
'Package in transit',
array(),
'Emails.Subject',
$orderLanguage->locale
),
$templateVars,
$customer->email,
$customer->firstname . ' ' . $customer->lastname,
null,
null,
null,
null,
_PS_MAIL_DIR_,
true,
(int) $order->id_shop
)) {
return true;
} else {
return false;
}
}
public function updateWs()
{
if (!parent::update()) {
return false;
}
$sendemail = (bool) Tools::getValue('sendemail', false);
if ($sendemail) {
$order = new Order((int) $this->id_order);
if (!Validate::isLoadedObject($order)) {
throw new PrestaShopException('Can\'t load Order object');
}
if (!$this->sendInTransitEmail($order)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderCartRuleCore extends ObjectModel
{
/** @var int */
public $id_order_cart_rule;
/** @var int */
public $id_order;
/** @var int */
public $id_cart_rule;
/** @var int */
public $id_order_invoice;
/** @var string */
public $name;
/** @var float value (tax incl.) of voucher */
public $value;
/** @var float value (tax excl.) of voucher */
public $value_tax_excl;
/** @var bool value : voucher gives free shipping or not */
public $free_shipping;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_cart_rule',
'primary' => 'id_order_cart_rule',
'fields' => array(
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_cart_rule' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_order_invoice' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'name' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'required' => true),
'value' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'value_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'free_shipping' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
),
);
protected $webserviceParameters = array(
'fields' => array(
'id_order' => array('xlink_resource' => 'orders'),
),
);
}

View File

@@ -0,0 +1,893 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderDetailCore extends ObjectModel
{
/** @var int */
public $id_order_detail;
/** @var int */
public $id_order;
/** @var int */
public $id_order_invoice;
/** @var int */
public $product_id;
/** @var int */
public $id_shop;
/** @var int */
public $product_attribute_id;
/** @var int */
public $id_customization;
/** @var string */
public $product_name;
/** @var int */
public $product_quantity;
/** @var int */
public $product_quantity_in_stock;
/** @var int */
public $product_quantity_return;
/** @var int */
public $product_quantity_refunded;
/** @var int */
public $product_quantity_reinjected;
/** @var float */
public $product_price;
/** @var float */
public $original_product_price;
/** @var float */
public $unit_price_tax_incl;
/** @var float */
public $unit_price_tax_excl;
/** @var float */
public $total_price_tax_incl;
/** @var float */
public $total_price_tax_excl;
/** @var float */
public $reduction_percent;
/** @var float */
public $reduction_amount;
/** @var float */
public $reduction_amount_tax_excl;
/** @var float */
public $reduction_amount_tax_incl;
/** @var float */
public $group_reduction;
/** @var float */
public $product_quantity_discount;
/** @var string */
public $product_ean13;
/** @var string */
public $product_isbn;
/** @var string */
public $product_upc;
/** @var string */
public $product_reference;
/** @var string */
public $product_supplier_reference;
/** @var float */
public $product_weight;
/** @var float */
public $ecotax;
/** @var float */
public $ecotax_tax_rate;
/** @var int */
public $discount_quantity_applied;
/** @var string */
public $download_hash;
/** @var int */
public $download_nb;
/** @var datetime */
public $download_deadline;
/** @var string $tax_name * */
public $tax_name;
/** @var float $tax_rate * */
public $tax_rate;
/** @var float $tax_computation_method * */
public $tax_computation_method;
/** @var int Id tax rules group */
public $id_tax_rules_group;
/** @var int Id warehouse */
public $id_warehouse;
/** @var float additional shipping price tax excl */
public $total_shipping_price_tax_excl;
/** @var float additional shipping price tax incl */
public $total_shipping_price_tax_incl;
/** @var float */
public $purchase_supplier_price;
/** @var float */
public $original_wholesale_price;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_detail',
'primary' => 'id_order_detail',
'fields' => array(
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_order_invoice' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_warehouse' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_shop' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'product_id' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'product_attribute_id' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_customization' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'product_name' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true),
'product_quantity' => array('type' => self::TYPE_INT, 'validate' => 'isInt', 'required' => true),
'product_quantity_in_stock' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'product_quantity_return' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'product_quantity_refunded' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'product_quantity_reinjected' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'product_price' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice', 'required' => true),
'reduction_percent' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'reduction_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'reduction_amount_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'reduction_amount_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'group_reduction' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'product_quantity_discount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'product_ean13' => array('type' => self::TYPE_STRING, 'validate' => 'isEan13'),
'product_isbn' => array('type' => self::TYPE_STRING, 'validate' => 'isIsbn'),
'product_upc' => array('type' => self::TYPE_STRING, 'validate' => 'isUpc'),
'product_reference' => array('type' => self::TYPE_STRING, 'validate' => 'isReference'),
'product_supplier_reference' => array('type' => self::TYPE_STRING, 'validate' => 'isReference'),
'product_weight' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'tax_name' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'tax_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'tax_computation_method' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'id_tax_rules_group' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'ecotax' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'ecotax_tax_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'discount_quantity_applied' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'download_hash' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'download_nb' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
'download_deadline' => array('type' => self::TYPE_DATE, 'validate' => 'isDateFormat'),
'unit_price_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'unit_price_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'total_price_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'total_price_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'total_shipping_price_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'total_shipping_price_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'purchase_supplier_price' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'original_product_price' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'original_wholesale_price' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
),
);
protected $webserviceParameters = array(
'fields' => array(
'id_order' => array('xlink_resource' => 'orders'),
'product_id' => array('xlink_resource' => 'products'),
'product_attribute_id' => array('xlink_resource' => 'combinations'),
'product_quantity_reinjected' => array(),
'group_reduction' => array(),
'discount_quantity_applied' => array(),
'download_hash' => array(),
'download_deadline' => array(),
),
'hidden_fields' => array('tax_rate', 'tax_name'),
'associations' => array(
'taxes' => array('resource' => 'tax', 'getter' => 'getWsTaxes', 'setter' => false,
'fields' => array('id' => array()),
),
),
);
/** @var bool */
protected $outOfStock = false;
/** @var TaxCalculator object */
protected $tax_calculator = null;
/** @var Address object */
protected $vat_address = null;
/** @var Address object */
protected $specificPrice = null;
/** @var Customer object */
protected $customer = null;
/** @var Context object */
protected $context = null;
public function __construct($id = null, $id_lang = null, $context = null)
{
$this->context = $context;
$id_shop = null;
if ($this->context != null && isset($this->context->shop)) {
$id_shop = $this->context->shop->id;
}
parent::__construct($id, $id_lang, $id_shop);
if ($context == null) {
$context = Context::getContext();
}
$this->context = $context->cloneContext();
}
public function delete()
{
if (!$res = parent::delete()) {
return false;
}
Db::getInstance()->delete('order_detail_tax', 'id_order_detail=' . (int) $this->id);
return $res;
}
protected function setContext($id_shop)
{
if ($this->context->shop->id != $id_shop) {
$this->context->shop = new Shop((int) $id_shop);
}
}
public static function getDownloadFromHash($hash)
{
if ($hash == '') {
return false;
}
$sql = 'SELECT *
FROM `' . _DB_PREFIX_ . 'order_detail` od
LEFT JOIN `' . _DB_PREFIX_ . 'product_download` pd ON (od.`product_id`=pd.`id_product`)
WHERE od.`download_hash` = \'' . pSQL((string) $hash) . '\'
AND pd.`active` = 1';
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow($sql);
}
public static function incrementDownload($id_order_detail, $increment = 1)
{
$sql = 'UPDATE `' . _DB_PREFIX_ . 'order_detail`
SET `download_nb` = `download_nb` + ' . (int) $increment . '
WHERE `id_order_detail`= ' . (int) $id_order_detail . '
LIMIT 1';
return Db::getInstance()->execute($sql);
}
/**
* Returns the tax calculator associated to this order detail.
*
* @since 1.5.0.1
*
* @return TaxCalculator
*/
public function getTaxCalculator()
{
return OrderDetail::getTaxCalculatorStatic($this->id);
}
/**
* Return the tax calculator associated to this order_detail.
*
* @since 1.5.0.1
*
* @param int $id_order_detail
*
* @return TaxCalculator
*/
public static function getTaxCalculatorStatic($id_order_detail)
{
$sql = 'SELECT t.*, d.`tax_computation_method`
FROM `' . _DB_PREFIX_ . 'order_detail_tax` t
LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` d ON (d.`id_order_detail` = t.`id_order_detail`)
WHERE d.`id_order_detail` = ' . (int) $id_order_detail;
$computation_method = 1;
$taxes = array();
if ($results = Db::getInstance()->executeS($sql)) {
foreach ($results as $result) {
$taxes[] = new Tax((int) $result['id_tax']);
}
$computation_method = $result['tax_computation_method'];
}
return new TaxCalculator($taxes, $computation_method);
}
/**
* Save the tax calculator.
*
* @since 1.5.0.1
* @deprecated Functionality moved to Order::updateOrderDetailTax
* because we need the full order object to do a good job here.
* Will no longer be supported after 1.6.1
*
* @return bool
*/
public function saveTaxCalculator(Order $order, $replace = false)
{
// Nothing to save
if ($this->tax_calculator == null) {
return true;
}
if (!($this->tax_calculator instanceof TaxCalculator)) {
return false;
}
if (count($this->tax_calculator->taxes) == 0) {
return true;
}
if ($order->total_products <= 0) {
return true;
}
$shipping_tax_amount = 0;
foreach ($order->getCartRules() as $cart_rule) {
if ($cart_rule['free_shipping']) {
$shipping_tax_amount = $order->total_shipping_tax_excl;
break;
}
}
$ratio = $this->unit_price_tax_excl / $order->total_products;
$order_reduction_amount = ($order->total_discounts_tax_excl - $shipping_tax_amount) * $ratio;
$discounted_price_tax_excl = $this->unit_price_tax_excl - $order_reduction_amount;
$values = '';
foreach ($this->tax_calculator->getTaxesAmount($discounted_price_tax_excl) as $id_tax => $amount) {
switch (Configuration::get('PS_ROUND_TYPE')) {
case Order::ROUND_ITEM:
$unit_amount = (float) Tools::ps_round($amount, _PS_PRICE_COMPUTE_PRECISION_);
$total_amount = $unit_amount * $this->product_quantity;
break;
case Order::ROUND_LINE:
$unit_amount = $amount;
$total_amount = Tools::ps_round($unit_amount * $this->product_quantity, _PS_PRICE_COMPUTE_PRECISION_);
break;
case Order::ROUND_TOTAL:
$unit_amount = $amount;
$total_amount = $unit_amount * $this->product_quantity;
break;
}
$values .= '(' . (int) $this->id . ',' . (int) $id_tax . ',' . (float) $unit_amount . ',' . (float) $total_amount . '),';
}
if ($replace) {
Db::getInstance()->execute('DELETE FROM `' . _DB_PREFIX_ . 'order_detail_tax` WHERE id_order_detail=' . (int) $this->id);
}
$values = rtrim($values, ',');
$sql = 'INSERT INTO `' . _DB_PREFIX_ . 'order_detail_tax` (id_order_detail, id_tax, unit_amount, total_amount)
VALUES ' . $values;
return Db::getInstance()->execute($sql);
}
public function updateTaxAmount($order)
{
$this->setContext((int) $this->id_shop);
$address = new Address((int) $order->{Configuration::get('PS_TAX_ADDRESS_TYPE')});
$tax_manager = TaxManagerFactory::getManager($address, (int) Product::getIdTaxRulesGroupByIdProduct((int) $this->product_id, $this->context));
$this->tax_calculator = $tax_manager->getTaxCalculator();
return $this->saveTaxCalculator($order, true);
}
/**
* Get a detailed order list of an id_order.
*
* @param int $id_order
*
* @return array
*/
public static function getList($id_order)
{
return Db::getInstance()->executeS('SELECT * FROM `' . _DB_PREFIX_ . 'order_detail` WHERE `id_order` = ' . (int) $id_order);
}
public function getTaxList()
{
return self::getTaxList($this->id);
}
public static function getTaxListStatic($id_order_detail)
{
$sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'order_detail_tax`
WHERE `id_order_detail` = ' . (int) $id_order_detail;
return Db::getInstance()->executeS($sql);
}
/**
* Set virtual product information
*
* @param array $product
*/
protected function setVirtualProductInformation($product)
{
// Add some informations for virtual products
$this->download_deadline = '0000-00-00 00:00:00';
$this->download_hash = null;
if ($id_product_download = ProductDownload::getIdFromIdProduct((int) $product['id_product'])) {
$product_download = new ProductDownload((int) $id_product_download);
$this->download_deadline = $product_download->getDeadLine();
$this->download_hash = $product_download->getHash();
unset($product_download);
}
}
/**
* Check the order status.
*
* @param array $product
* @param int $id_order_state
*/
protected function checkProductStock($product, $id_order_state)
{
if ($id_order_state != Configuration::get('PS_OS_CANCELED') && $id_order_state != Configuration::get('PS_OS_ERROR')) {
$update_quantity = true;
if (!StockAvailable::dependsOnStock($product['id_product'])) {
$update_quantity = StockAvailable::updateQuantity($product['id_product'], $product['id_product_attribute'], -(int) $product['cart_quantity']);
}
if ($update_quantity) {
$product['stock_quantity'] -= $product['cart_quantity'];
}
if ($product['stock_quantity'] < 0 && Configuration::get('PS_STOCK_MANAGEMENT')) {
$this->outOfStock = true;
}
Product::updateDefaultAttribute($product['id_product']);
}
}
/**
* Apply tax to the product.
*
* @param object $order
* @param array $product
*/
protected function setProductTax(Order $order, $product)
{
$this->ecotax = Tools::convertPrice((float) ($product['ecotax']), (int) ($order->id_currency));
// Exclude VAT
if (!Tax::excludeTaxeOption()) {
$this->setContext((int) $product['id_shop']);
$this->id_tax_rules_group = (int) Product::getIdTaxRulesGroupByIdProduct((int) $product['id_product'], $this->context);
$tax_manager = TaxManagerFactory::getManager($this->vat_address, $this->id_tax_rules_group);
$this->tax_calculator = $tax_manager->getTaxCalculator();
$this->tax_computation_method = (int) $this->tax_calculator->computation_method;
}
$this->ecotax_tax_rate = 0;
if (!empty($product['ecotax'])) {
$this->ecotax_tax_rate = Tax::getProductEcotaxRate($order->{Configuration::get('PS_TAX_ADDRESS_TYPE')});
}
}
/**
* Set specific price of the product.
*
* @param object $order
*/
protected function setSpecificPrice(Order $order, $product = null)
{
$this->reduction_amount = 0.00;
$this->reduction_percent = 0.00;
$this->reduction_amount_tax_incl = 0.00;
$this->reduction_amount_tax_excl = 0.00;
if ($this->specificPrice) {
switch ($this->specificPrice['reduction_type']) {
case 'percentage':
$this->reduction_percent = (float) $this->specificPrice['reduction'] * 100;
break;
case 'amount':
$price = Tools::convertPrice($this->specificPrice['reduction'], $order->id_currency);
$this->reduction_amount = !$this->specificPrice['id_currency'] ? (float) $price : (float) $this->specificPrice['reduction'];
if ($product !== null) {
$this->setContext((int) $product['id_shop']);
}
$id_tax_rules = (int) Product::getIdTaxRulesGroupByIdProduct((int) $this->specificPrice['id_product'], $this->context);
$tax_manager = TaxManagerFactory::getManager($this->vat_address, $id_tax_rules);
$this->tax_calculator = $tax_manager->getTaxCalculator();
if ($this->specificPrice['reduction_tax']) {
$this->reduction_amount_tax_incl = $this->reduction_amount;
$this->reduction_amount_tax_excl = Tools::ps_round($this->tax_calculator->removeTaxes($this->reduction_amount), _PS_PRICE_COMPUTE_PRECISION_);
} else {
$this->reduction_amount_tax_incl = Tools::ps_round($this->tax_calculator->addTaxes($this->reduction_amount), _PS_PRICE_COMPUTE_PRECISION_);
$this->reduction_amount_tax_excl = $this->reduction_amount;
}
break;
}
}
}
/**
* Set detailed product price to the order detail.
*
* @param object $order
* @param object $cart
* @param array $product
*/
protected function setDetailProductPrice(Order $order, Cart $cart, $product)
{
$this->setContext((int) $product['id_shop']);
Product::getPriceStatic((int) $product['id_product'], true, (int) $product['id_product_attribute'], 6, null, false, true, $product['cart_quantity'], false, (int) $order->id_customer, (int) $order->id_cart, (int) $order->{Configuration::get('PS_TAX_ADDRESS_TYPE')}, $specific_price, true, true, $this->context);
$this->specificPrice = $specific_price;
$this->original_product_price = Product::getPriceStatic($product['id_product'], false, (int) $product['id_product_attribute'], 6, null, false, false, 1, false, null, null, null, $null, true, true, $this->context);
$this->product_price = $this->original_product_price;
$this->unit_price_tax_incl = (float) $product['price_wt'];
$this->unit_price_tax_excl = (float) $product['price'];
$this->total_price_tax_incl = (float) $product['total_wt'];
$this->total_price_tax_excl = (float) $product['total'];
$this->purchase_supplier_price = (float) $product['wholesale_price'];
if ($product['id_supplier'] > 0 && ($supplier_price = ProductSupplier::getProductPrice((int) $product['id_supplier'], $product['id_product'], $product['id_product_attribute'], true)) > 0) {
$this->purchase_supplier_price = (float) $supplier_price;
}
$this->setSpecificPrice($order, $product);
$this->group_reduction = (float) Group::getReduction((int) $order->id_customer);
$shop_id = $this->context->shop->id;
$quantity_discount = SpecificPrice::getQuantityDiscount(
(int) $product['id_product'],
$shop_id,
(int) $cart->id_currency,
(int) $this->vat_address->id_country,
(int) $this->customer->id_default_group,
(int) $product['cart_quantity'],
false,
null,
null,
$null,
true,
true,
$this->context
);
$unit_price = Product::getPriceStatic(
(int) $product['id_product'],
true,
($product['id_product_attribute'] ? (int) ($product['id_product_attribute']) : null),
2,
null,
false,
true,
1,
false,
(int) $order->id_customer,
null,
(int) $order->{Configuration::get('PS_TAX_ADDRESS_TYPE')},
$null,
true,
true,
$this->context
);
$this->product_quantity_discount = 0.00;
if ($quantity_discount) {
$this->product_quantity_discount = $unit_price;
if (Product::getTaxCalculationMethod((int) $order->id_customer) == PS_TAX_EXC) {
$this->product_quantity_discount = Tools::ps_round($unit_price, 2);
}
if (isset($this->tax_calculator)) {
$this->product_quantity_discount -= $this->tax_calculator->addTaxes($quantity_discount['price']);
}
}
$this->discount_quantity_applied = (($this->specificPrice && $this->specificPrice['from_quantity'] > 1) ? 1 : 0);
}
/**
* Create an order detail liable to an id_order.
*
* @param object $order
* @param object $cart
* @param array $product
* @param int $id_order_status
* @param int $id_order_invoice
* @param bool $use_taxes set to false if you don't want to use taxes
*/
protected function create(Order $order, Cart $cart, $product, $id_order_state, $id_order_invoice, $use_taxes = true, $id_warehouse = 0)
{
if ($use_taxes) {
$this->tax_calculator = new TaxCalculator();
}
$this->id = null;
$this->product_id = (int) $product['id_product'];
$this->product_attribute_id = $product['id_product_attribute'] ? (int) $product['id_product_attribute'] : 0;
$this->id_customization = $product['id_customization'] ? (int) $product['id_customization'] : 0;
$this->product_name = $product['name'] .
((isset($product['attributes']) && $product['attributes'] != null) ?
' - ' . $product['attributes'] : '');
$this->product_quantity = (int) $product['cart_quantity'];
$this->product_ean13 = empty($product['ean13']) ? null : pSQL($product['ean13']);
$this->product_isbn = empty($product['isbn']) ? null : pSQL($product['isbn']);
$this->product_upc = empty($product['upc']) ? null : pSQL($product['upc']);
$this->product_reference = empty($product['reference']) ? null : pSQL($product['reference']);
$this->product_supplier_reference = empty($product['supplier_reference']) ? null : pSQL($product['supplier_reference']);
$this->product_weight = $product['id_product_attribute'] ? (float) $product['weight_attribute'] : (float) $product['weight'];
$this->id_warehouse = $id_warehouse;
$product_quantity = (int) Product::getQuantity($this->product_id, $this->product_attribute_id, null, $cart);
$this->product_quantity_in_stock = ($product_quantity - (int) $product['cart_quantity'] < 0) ?
$product_quantity : (int) $product['cart_quantity'];
$this->setVirtualProductInformation($product);
$this->checkProductStock($product, $id_order_state);
if ($use_taxes) {
$this->setProductTax($order, $product);
}
$this->setShippingCost($order, $product);
$this->setDetailProductPrice($order, $cart, $product);
// Set order invoice id
$this->id_order_invoice = (int) $id_order_invoice;
// Set shop id
$this->id_shop = (int) $product['id_shop'];
// Add new entry to the table
$this->save();
if ($use_taxes) {
$this->saveTaxCalculator($order);
}
unset($this->tax_calculator);
}
/**
* Create a list of order detail for a specified id_order using cart.
*
* @param object $order
* @param object $cart
* @param int $id_order_status
* @param int $id_order_invoice
* @param bool $use_taxes set to false if you don't want to use taxes
*/
public function createList(Order $order, Cart $cart, $id_order_state, $product_list, $id_order_invoice = 0, $use_taxes = true, $id_warehouse = 0)
{
$this->vat_address = new Address((int) $order->{Configuration::get('PS_TAX_ADDRESS_TYPE')});
$this->customer = new Customer((int) $order->id_customer);
$this->id_order = $order->id;
$this->outOfStock = false;
foreach ($product_list as $product) {
$this->create($order, $cart, $product, $id_order_state, $id_order_invoice, $use_taxes, $id_warehouse);
}
unset(
$this->vat_address,
$products, $this->customer
);
}
/**
* Get the state of the current stock product.
*
* @return array
*/
public function getStockState()
{
return $this->outOfStock;
}
/**
* Set the additional shipping information.
*
* @param Order $order
* @param $product
*/
public function setShippingCost(Order $order, $product)
{
$tax_rate = 0;
$carrier = OrderInvoice::getCarrier((int) $this->id_order_invoice);
if (isset($carrier) && Validate::isLoadedObject($carrier)) {
$tax_rate = $carrier->getTaxesRate(new Address((int) $order->{Configuration::get('PS_TAX_ADDRESS_TYPE')}));
}
$this->total_shipping_price_tax_excl = (float) $product['additional_shipping_cost'];
$this->total_shipping_price_tax_incl = (float) ($this->total_shipping_price_tax_excl * (1 + ($tax_rate / 100)));
$this->total_shipping_price_tax_incl = Tools::ps_round($this->total_shipping_price_tax_incl, 2);
}
public function getWsTaxes()
{
$query = new DbQuery();
$query->select('id_tax as id');
$query->from('order_detail_tax', 'tax');
$query->leftJoin('order_detail', 'od', 'tax.`id_order_detail` = od.`id_order_detail`');
$query->where('od.`id_order_detail` = ' . (int) $this->id_order_detail);
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
}
public static function getCrossSells($id_product, $id_lang, $limit = 12)
{
if (!$id_product || !$id_lang) {
return;
}
$front = true;
if (!in_array(Context::getContext()->controller->controller_type, array('front', 'modulefront'))) {
$front = false;
}
$orders = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT o.id_order
FROM ' . _DB_PREFIX_ . 'orders o
LEFT JOIN ' . _DB_PREFIX_ . 'order_detail od ON (od.id_order = o.id_order)
WHERE o.valid = 1 AND od.product_id = ' . (int) $id_product);
if (count($orders)) {
$list = '';
foreach ($orders as $order) {
$list .= (int) $order['id_order'] . ',';
}
$list = rtrim($list, ',');
$order_products = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT DISTINCT od.product_id, p.id_product, pl.name, pl.link_rewrite, p.reference, i.id_image, product_shop.show_price,
cl.link_rewrite category, p.ean13, p.isbn, p.out_of_stock, p.id_category_default ' . (Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute,0) id_product_attribute' : '') . '
FROM ' . _DB_PREFIX_ . 'order_detail od
LEFT JOIN ' . _DB_PREFIX_ . 'product p ON (p.id_product = od.product_id)
' . Shop::addSqlAssociation('product', 'p') .
(Combination::isFeatureActive() ? 'LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute_shop` product_attribute_shop
ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop=' . (int) Context::getContext()->shop->id . ')' : '') . '
LEFT JOIN ' . _DB_PREFIX_ . 'product_lang pl ON (pl.id_product = od.product_id' . Shop::addSqlRestrictionOnLang('pl') . ')
LEFT JOIN ' . _DB_PREFIX_ . 'category_lang cl ON (cl.id_category = product_shop.id_category_default' . Shop::addSqlRestrictionOnLang('cl') . ')
LEFT JOIN ' . _DB_PREFIX_ . 'image i ON (i.id_product = od.product_id)
' . Shop::addSqlAssociation('image', 'i', true, 'image_shop.cover=1') . '
WHERE od.id_order IN (' . $list . ')
AND pl.id_lang = ' . (int) $id_lang . '
AND cl.id_lang = ' . (int) $id_lang . '
AND od.product_id != ' . (int) $id_product . '
AND product_shop.active = 1'
. ($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') . '
ORDER BY RAND()
LIMIT ' . (int) $limit . '
', true, false);
$tax_calc = Product::getTaxCalculationMethod();
if (is_array($order_products)) {
foreach ($order_products as &$order_product) {
$order_product['image'] = Context::getContext()->link->getImageLink(
$order_product['link_rewrite'],
(int) $order_product['product_id'] . '-' . (int) $order_product['id_image'],
ImageType::getFormattedName('medium')
);
$order_product['link'] = Context::getContext()->link->getProductLink(
(int) $order_product['product_id'],
$order_product['link_rewrite'],
$order_product['category'],
$order_product['ean13']
);
if ($tax_calc == 0 || $tax_calc == 2) {
$order_product['displayed_price'] = Product::getPriceStatic((int) $order_product['product_id'], true, null);
} elseif ($tax_calc == 1) {
$order_product['displayed_price'] = Product::getPriceStatic((int) $order_product['product_id'], false, null);
}
}
return Product::getProductsProperties($id_lang, $order_products);
}
}
}
public function add($autodate = true, $null_values = false)
{
foreach ($this->def['fields'] as $field => $data) {
if (!empty($data['required']) || !empty($data['lang'])) {
continue;
}
if ($this->validateField($field, $this->$field) !== true) {
$this->$field = '';
}
}
$this->original_wholesale_price = $this->getWholeSalePrice();
return parent::add($autodate = true, $null_values = false);
}
//return the product OR product attribute whole sale price
public function getWholeSalePrice()
{
$product = new Product($this->product_id);
$wholesale_price = $product->wholesale_price;
if ($this->product_attribute_id) {
$combination = new Combination((int) $this->product_attribute_id);
if ($combination && $combination->wholesale_price != '0.000000') {
$wholesale_price = $combination->wholesale_price;
}
}
return $wholesale_price;
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
/**
* @deprecated 1.5.0
*/
class OrderDiscountCore extends OrderCartRule
{
public function __get($key)
{
Tools::displayAsDeprecated();
if ($key == 'id_order_discount') {
return $this->id_order_cart_rule;
}
if ($key == 'id_discount') {
return $this->id_cart_rule;
}
return $this->{$key};
}
public function __set($key, $value)
{
Tools::displayAsDeprecated();
if ($key == 'id_order_discount') {
$this->id_order_cart_rule = $value;
}
if ($key == 'id_discount') {
$this->id_cart_rule = $value;
}
$this->{$key} = $value;
}
public function __call($method, $args)
{
Tools::displayAsDeprecated();
return call_user_func_array(array($this->parent, $method), $args);
}
}

View File

@@ -0,0 +1,618 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
use PrestaShop\PrestaShop\Adapter\StockManager as StockManagerAdapter;
use PrestaShop\PrestaShop\Core\Stock\StockManager;
class OrderHistoryCore extends ObjectModel
{
/** @var int Order id */
public $id_order;
/** @var int Order status id */
public $id_order_state;
/** @var int Employee id for this history entry */
public $id_employee;
/** @var string Object creation date */
public $date_add;
/** @var string Object last modification date */
public $date_upd;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_history',
'primary' => 'id_order_history',
'fields' => array(
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_order_state' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_employee' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
/**
* @see ObjectModel::$webserviceParameters
*/
protected $webserviceParameters = array(
'objectsNodeName' => 'order_histories',
'fields' => array(
'id_employee' => array('xlink_resource' => 'employees'),
'id_order_state' => array('required' => true, 'xlink_resource' => 'order_states'),
'id_order' => array('xlink_resource' => 'orders'),
),
'objectMethods' => array(
'add' => 'addWs',
),
);
/**
* Sets the new state of the given order.
*
* @param int $new_order_state
* @param int/object $id_order
* @param bool $use_existing_payment
*/
public function changeIdOrderState($new_order_state, $id_order, $use_existing_payment = false)
{
if (!$new_order_state || !$id_order) {
return;
}
if (!is_object($id_order) && is_numeric($id_order)) {
$order = new Order((int) $id_order);
} elseif (is_object($id_order)) {
$order = $id_order;
} else {
return;
}
ShopUrl::cacheMainDomainForShop($order->id_shop);
$new_os = new OrderState((int) $new_order_state, $order->id_lang);
$old_os = $order->getCurrentOrderState();
// executes hook
if (in_array($new_os->id, array(Configuration::get('PS_OS_PAYMENT'), Configuration::get('PS_OS_WS_PAYMENT')))) {
Hook::exec('actionPaymentConfirmation', array('id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
}
// executes hook
Hook::exec('actionOrderStatusUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
if (Validate::isLoadedObject($order) && ($new_os instanceof OrderState)) {
$context = Context::getContext();
// An email is sent the first time a virtual item is validated
$virtual_products = $order->getVirtualProducts();
if ($virtual_products && (!$old_os || !$old_os->logable) && $new_os && $new_os->logable) {
$assign = array();
foreach ($virtual_products as $key => $virtual_product) {
$id_product_download = ProductDownload::getIdFromIdProduct($virtual_product['product_id']);
$product_download = new ProductDownload($id_product_download);
// If this virtual item has an associated file, we'll provide the link to download the file in the email
if ($product_download->display_filename != '') {
$assign[$key]['name'] = $product_download->display_filename;
$dl_link = $product_download->getTextLink(false, $virtual_product['download_hash'])
. '&id_order=' . (int) $order->id
. '&secure_key=' . $order->secure_key;
$assign[$key]['link'] = $dl_link;
if (isset($virtual_product['download_deadline']) && $virtual_product['download_deadline'] != '0000-00-00 00:00:00') {
$assign[$key]['deadline'] = Tools::displayDate($virtual_product['download_deadline']);
}
if ($product_download->nb_downloadable != 0) {
$assign[$key]['downloadable'] = (int) $product_download->nb_downloadable;
}
}
}
$customer = new Customer((int) $order->id_customer);
$links = '<ul>';
foreach ($assign as $product) {
$links .= '<li>';
$links .= '<a href="' . $product['link'] . '">' . Tools::htmlentitiesUTF8($product['name']) . '</a>';
if (isset($product['deadline'])) {
$links .= '&nbsp;' . $this->trans('expires on %s.', array($product['deadline']), 'Admin.Orderscustomers.Notification');
}
if (isset($product['downloadable'])) {
$links .= '&nbsp;' . $this->trans('downloadable %d time(s)', array((int) $product['downloadable']), 'Admin.Orderscustomers.Notification');
}
$links .= '</li>';
}
$links .= '</ul>';
$data = array(
'{lastname}' => $customer->lastname,
'{firstname}' => $customer->firstname,
'{id_order}' => (int) $order->id,
'{order_name}' => $order->getUniqReference(),
'{nbProducts}' => count($virtual_products),
'{virtualProducts}' => $links,
);
// If there is at least one downloadable file
if (!empty($assign)) {
$orderLanguage = new Language((int) $order->id_lang);
Mail::Send(
(int) $order->id_lang,
'download_product',
Context::getContext()->getTranslator()->trans(
'The virtual product that you bought is available for download',
array(),
'Emails.Subject',
$orderLanguage->locale
),
$data,
$customer->email,
$customer->firstname . ' ' . $customer->lastname,
null,
null,
null,
null,
_PS_MAIL_DIR_,
false,
(int) $order->id_shop
);
}
}
/** @since 1.5.0 : gets the stock manager */
$manager = null;
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
$manager = StockManagerFactory::getManager();
}
$error_or_canceled_statuses = array(Configuration::get('PS_OS_ERROR'), Configuration::get('PS_OS_CANCELED'));
$employee = null;
if (!(int) $this->id_employee || !Validate::isLoadedObject(($employee = new Employee((int) $this->id_employee)))) {
if (!Validate::isLoadedObject($old_os) && $context != null) {
// First OrderHistory, there is no $old_os, so $employee is null before here
$employee = $context->employee; // filled if from BO and order created (because no old_os)
if ($employee) {
$this->id_employee = $employee->id;
}
} else {
$employee = null;
}
}
// foreach products of the order
foreach ($order->getProductsDetail() as $product) {
if (Validate::isLoadedObject($old_os)) {
// if becoming logable => adds sale
if ($new_os->logable && !$old_os->logable) {
ProductSale::addProductSale($product['product_id'], $product['product_quantity']);
// @since 1.5.0 - Stock Management
if (!Pack::isPack($product['product_id']) &&
in_array($old_os->id, $error_or_canceled_statuses) &&
!StockAvailable::dependsOnStock($product['id_product'], (int) $order->id_shop)) {
StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int) $product['product_quantity'], $order->id_shop);
}
} elseif (!$new_os->logable && $old_os->logable) {
// if becoming unlogable => removes sale
ProductSale::removeProductSale($product['product_id'], $product['product_quantity']);
// @since 1.5.0 - Stock Management
if (!Pack::isPack($product['product_id']) &&
in_array($new_os->id, $error_or_canceled_statuses) &&
!StockAvailable::dependsOnStock($product['id_product'])) {
StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
}
} elseif (!$new_os->logable && !$old_os->logable &&
in_array($new_os->id, $error_or_canceled_statuses) &&
!in_array($old_os->id, $error_or_canceled_statuses) &&
!StockAvailable::dependsOnStock($product['id_product'])
) {
// if waiting for payment => payment error/canceled
StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], (int) $product['product_quantity'], $order->id_shop);
}
}
// From here, there is 2 cases : $old_os exists, and we can test shipped state evolution,
// Or old_os does not exists, and we should consider that initial shipped state is 0 (to allow decrease of stocks)
// @since 1.5.0 : if the order is being shipped and this products uses the advanced stock management :
// decrements the physical stock using $id_warehouse
if ($new_os->shipped == 1 && (!Validate::isLoadedObject($old_os) || $old_os->shipped == 0) &&
Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') &&
Warehouse::exists($product['id_warehouse']) &&
$manager != null &&
(int) $product['advanced_stock_management'] == 1) {
// gets the warehouse
$warehouse = new Warehouse($product['id_warehouse']);
// decrements the stock (if it's a pack, the StockManager does what is needed)
$manager->removeProduct(
$product['product_id'],
$product['product_attribute_id'],
$warehouse,
($product['product_quantity'] - $product['product_quantity_refunded'] - $product['product_quantity_return']),
Configuration::get('PS_STOCK_CUSTOMER_ORDER_REASON'),
true,
(int) $order->id,
0,
$employee
);
} elseif ($new_os->shipped == 0 && Validate::isLoadedObject($old_os) && $old_os->shipped == 1 &&
Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') &&
Warehouse::exists($product['id_warehouse']) &&
$manager != null &&
(int) $product['advanced_stock_management'] == 1
) {
// @since.1.5.0 : if the order was shipped, and is not anymore, we need to restock products
// if the product is a pack, we restock every products in the pack using the last negative stock mvts
if (Pack::isPack($product['product_id'])) {
$pack_products = Pack::getItems($product['product_id'], Configuration::get('PS_LANG_DEFAULT', null, null, $order->id_shop));
foreach ($pack_products as $pack_product) {
if ($pack_product->advanced_stock_management == 1) {
$mvts = StockMvt::getNegativeStockMvts($order->id, $pack_product->id, 0, $pack_product->pack_quantity * $product['product_quantity']);
foreach ($mvts as $mvt) {
$manager->addProduct(
$pack_product->id,
0,
new Warehouse($mvt['id_warehouse']),
$mvt['physical_quantity'],
null,
$mvt['price_te'],
true,
null,
$employee
);
}
if (!StockAvailable::dependsOnStock($product['id_product'])) {
StockAvailable::updateQuantity($pack_product->id, 0, (int) $pack_product->pack_quantity * $product['product_quantity'], $order->id_shop);
}
}
}
} else {
// else, it's not a pack, re-stock using the last negative stock mvts
$mvts = StockMvt::getNegativeStockMvts(
$order->id,
$product['product_id'],
$product['product_attribute_id'],
($product['product_quantity'] - $product['product_quantity_refunded'] - $product['product_quantity_return'])
);
foreach ($mvts as $mvt) {
$manager->addProduct(
$product['product_id'],
$product['product_attribute_id'],
new Warehouse($mvt['id_warehouse']),
$mvt['physical_quantity'],
null,
$mvt['price_te'],
true
);
}
}
}
// Save movement if :
// not Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')
// new_os->shipped != old_os->shipped
if (Validate::isLoadedObject($old_os) && Validate::isLoadedObject($new_os) && $new_os->shipped != $old_os->shipped && !Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')) {
$product_quantity = (int) ($product['product_quantity'] - $product['product_quantity_refunded'] - $product['product_quantity_return']);
if ($product_quantity > 0) {
$current_shop_context_type = Context::getContext()->shop->getContextType();
if ($current_shop_context_type !== Shop::CONTEXT_SHOP) {
//change to order shop context
$current_shop_group_id = Context::getContext()->shop->getContextShopGroupID();
Context::getContext()->shop->setContext(Shop::CONTEXT_SHOP, $order->id_shop);
}
(new StockManager())->saveMovement(
(int) $product['product_id'],
(int) $product['product_attribute_id'],
(int) $product_quantity * ($new_os->shipped == 1 ? -1 : 1),
array(
'id_order' => $order->id,
'id_stock_mvt_reason' => ($new_os->shipped == 1 ? Configuration::get('PS_STOCK_CUSTOMER_ORDER_REASON') : Configuration::get('PS_STOCK_CUSTOMER_ORDER_CANCEL_REASON')),
)
);
//back to current shop context
if ($current_shop_context_type !== Shop::CONTEXT_SHOP) {
Context::getContext()->shop->setContext($current_shop_context_type, $current_shop_group_id);
}
}
}
}
}
$this->id_order_state = (int) $new_order_state;
// changes invoice number of order ?
if (!Validate::isLoadedObject($new_os) || !Validate::isLoadedObject($order)) {
die(Tools::displayError($this->trans('Invalid new order status', array(), 'Admin.Orderscustomers.Notification')));
}
// the order is valid if and only if the invoice is available and the order is not cancelled
$order->current_state = $this->id_order_state;
$order->valid = $new_os->logable;
$order->update();
if ($new_os->invoice && !$order->invoice_number) {
$order->setInvoice($use_existing_payment);
} elseif ($new_os->delivery && !$order->delivery_number) {
$order->setDeliverySlip();
}
// set orders as paid
if ($new_os->paid == 1) {
$invoices = $order->getInvoicesCollection();
if ($order->total_paid != 0) {
$payment_method = Module::getInstanceByName($order->module);
}
foreach ($invoices as $invoice) {
/** @var OrderInvoice $invoice */
$rest_paid = $invoice->getRestPaid();
if ($rest_paid > 0) {
$payment = new OrderPayment();
$payment->order_reference = Tools::substr($order->reference, 0, 9);
$payment->id_currency = $order->id_currency;
$payment->amount = $rest_paid;
if ($order->total_paid != 0) {
$payment->payment_method = $payment_method->displayName;
} else {
$payment->payment_method = null;
}
// Update total_paid_real value for backward compatibility reasons
if ($payment->id_currency == $order->id_currency) {
$order->total_paid_real += $payment->amount;
} else {
$order->total_paid_real += Tools::ps_round(Tools::convertPrice($payment->amount, $payment->id_currency, false), 2);
}
$order->save();
$payment->conversion_rate = ($order ? $order->conversion_rate : 1);
$payment->save();
Db::getInstance()->execute('
INSERT INTO `' . _DB_PREFIX_ . 'order_invoice_payment` (`id_order_invoice`, `id_order_payment`, `id_order`)
VALUES(' . (int) $invoice->id . ', ' . (int) $payment->id . ', ' . (int) $order->id . ')');
}
}
}
// updates delivery date even if it was already set by another state change
if ($new_os->delivery) {
$order->setDelivery();
}
// executes hook
Hook::exec('actionOrderStatusPostUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int) $order->id), null, false, true, false, $order->id_shop);
// sync all stock
(new StockManagerAdapter())->updatePhysicalProductQuantity(
(int) $order->id_shop,
(int) Configuration::get('PS_OS_ERROR'),
(int) Configuration::get('PS_OS_CANCELED'),
null,
(int) $order->id
);
ShopUrl::resetMainDomainCache();
}
/**
* Returns the last order status.
*
* @param int $id_order
*
* @return OrderState|bool
*
* @deprecated 1.5.0.4
* @see Order->current_state
*/
public static function getLastOrderState($id_order)
{
Tools::displayAsDeprecated();
$id_order_state = Db::getInstance()->getValue('
SELECT `id_order_state`
FROM `' . _DB_PREFIX_ . 'order_history`
WHERE `id_order` = ' . (int) $id_order . '
ORDER BY `date_add` DESC, `id_order_history` DESC');
// returns false if there is no state
if (!$id_order_state) {
return false;
}
// else, returns an OrderState object
return new OrderState($id_order_state, Configuration::get('PS_LANG_DEFAULT'));
}
/**
* @param bool $autodate Optional
* @param array $template_vars Optional
* @param Context $context Deprecated
*
* @return bool
*/
public function addWithemail($autodate = true, $template_vars = false, Context $context = null)
{
$order = new Order($this->id_order);
if (!$this->add($autodate)) {
return false;
}
if (!$this->sendEmail($order, $template_vars)) {
return false;
}
return true;
}
public function sendEmail($order, $template_vars = false)
{
$result = Db::getInstance()->getRow('
SELECT osl.`template`, c.`lastname`, c.`firstname`, osl.`name` AS osname, c.`email`, os.`module_name`, os.`id_order_state`, os.`pdf_invoice`, os.`pdf_delivery`
FROM `' . _DB_PREFIX_ . 'order_history` oh
LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON oh.`id_order` = o.`id_order`
LEFT JOIN `' . _DB_PREFIX_ . 'customer` c ON o.`id_customer` = c.`id_customer`
LEFT JOIN `' . _DB_PREFIX_ . 'order_state` os ON oh.`id_order_state` = os.`id_order_state`
LEFT JOIN `' . _DB_PREFIX_ . 'order_state_lang` osl ON (os.`id_order_state` = osl.`id_order_state` AND osl.`id_lang` = o.`id_lang`)
WHERE oh.`id_order_history` = ' . (int) $this->id . ' AND os.`send_email` = 1');
if (isset($result['template']) && Validate::isEmail($result['email'])) {
ShopUrl::cacheMainDomainForShop($order->id_shop);
$topic = $result['osname'];
$carrierUrl = '';
if (Validate::isLoadedObject($carrier = new Carrier((int) $order->id_carrier, $order->id_lang))) {
$carrierUrl = $carrier->url;
}
$data = array(
'{lastname}' => $result['lastname'],
'{firstname}' => $result['firstname'],
'{id_order}' => (int) $this->id_order,
'{order_name}' => $order->getUniqReference(),
'{followup}' => str_replace('@', $order->getWsShippingNumber(), $carrierUrl),
'{shipping_number}' => $order->getWsShippingNumber(),
);
if ($result['module_name']) {
$module = Module::getInstanceByName($result['module_name']);
if (Validate::isLoadedObject($module) && isset($module->extra_mail_vars) && is_array($module->extra_mail_vars)) {
$data = array_merge($data, $module->extra_mail_vars);
}
}
if (is_array($template_vars)) {
$data = array_merge($data, $template_vars);
}
$data['{total_paid}'] = Tools::displayPrice((float) $order->total_paid, new Currency((int) $order->id_currency), false);
if (Validate::isLoadedObject($order)) {
// Attach invoice and / or delivery-slip if they exists and status is set to attach them
if (($result['pdf_invoice'] || $result['pdf_delivery'])) {
$context = Context::getContext();
$invoice = $order->getInvoicesCollection();
$file_attachement = array();
if ($result['pdf_invoice'] && (int) Configuration::get('PS_INVOICE') && $order->invoice_number) {
Hook::exec('actionPDFInvoiceRender', array('order_invoice_list' => $invoice));
$pdf = new PDF($invoice, PDF::TEMPLATE_INVOICE, $context->smarty);
$file_attachement['invoice']['content'] = $pdf->render(false);
$file_attachement['invoice']['name'] = Configuration::get('PS_INVOICE_PREFIX', (int) $order->id_lang, null, $order->id_shop) . sprintf('%06d', $order->invoice_number) . '.pdf';
$file_attachement['invoice']['mime'] = 'application/pdf';
}
if ($result['pdf_delivery'] && $order->delivery_number) {
$pdf = new PDF($invoice, PDF::TEMPLATE_DELIVERY_SLIP, $context->smarty);
$file_attachement['delivery']['content'] = $pdf->render(false);
$file_attachement['delivery']['name'] = Configuration::get('PS_DELIVERY_PREFIX', Context::getContext()->language->id, null, $order->id_shop) . sprintf('%06d', $order->delivery_number) . '.pdf';
$file_attachement['delivery']['mime'] = 'application/pdf';
}
} else {
$file_attachement = null;
}
if (!Mail::Send(
(int) $order->id_lang,
$result['template'],
$topic,
$data,
$result['email'],
$result['firstname'] . ' ' . $result['lastname'],
null,
null,
$file_attachement,
null,
_PS_MAIL_DIR_,
false,
(int) $order->id_shop
)) {
return false;
}
}
ShopUrl::resetMainDomainCache();
}
return true;
}
public function add($autodate = true, $null_values = false)
{
if (!parent::add($autodate)) {
return false;
}
$order = new Order((int) $this->id_order);
// Update id_order_state attribute in Order
$order->current_state = $this->id_order_state;
$order->update();
Hook::exec('actionOrderHistoryAddAfter', array('order_history' => $this), null, false, true, false, $order->id_shop);
return true;
}
/**
* @return int
*/
public function isValidated()
{
return Db::getInstance()->getValue('
SELECT COUNT(oh.`id_order_history`) AS nb
FROM `' . _DB_PREFIX_ . 'order_state` os
LEFT JOIN `' . _DB_PREFIX_ . 'order_history` oh ON (os.`id_order_state` = oh.`id_order_state`)
WHERE oh.`id_order` = ' . (int) $this->id_order . '
AND os.`logable` = 1');
}
/**
* Add method for webservice create resource Order History
* If sendemail=1 GET parameter is present sends email to customer otherwise does not.
*
* @return bool
*/
public function addWs()
{
$sendemail = (bool) Tools::getValue('sendemail', false);
$this->changeIdOrderState($this->id_order_state, $this->id_order);
if ($sendemail) {
//Mail::Send requires link object on context and is not set when getting here
$context = Context::getContext();
if ($context->link == null) {
$protocol_link = (Tools::usingSecureMode() && Configuration::get('PS_SSL_ENABLED')) ? 'https://' : 'http://';
$protocol_content = (Tools::usingSecureMode() && Configuration::get('PS_SSL_ENABLED')) ? 'https://' : 'http://';
$context->link = new Link($protocol_link, $protocol_content);
}
return $this->addWithemail();
} else {
return $this->add();
}
}
}

View File

@@ -0,0 +1,940 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderInvoiceCore extends ObjectModel
{
const TAX_EXCL = 0;
const TAX_INCL = 1;
const DETAIL = 2;
/** @var int */
public $id_order;
/** @var int */
public $number;
/** @var int */
public $delivery_number;
/** @var int */
public $delivery_date = '0000-00-00 00:00:00';
/** @var float */
public $total_discount_tax_excl;
/** @var float */
public $total_discount_tax_incl;
/** @var float */
public $total_paid_tax_excl;
/** @var float */
public $total_paid_tax_incl;
/** @var float */
public $total_products;
/** @var float */
public $total_products_wt;
/** @var float */
public $total_shipping_tax_excl;
/** @var float */
public $total_shipping_tax_incl;
/** @var int */
public $shipping_tax_computation_method;
/** @var float */
public $total_wrapping_tax_excl;
/** @var float */
public $total_wrapping_tax_incl;
/** @var string shop address */
public $shop_address;
/** @var string note */
public $note;
/** @var int */
public $date_add;
/** @var array Total paid cache */
protected static $_total_paid_cache = array();
/** @var Order * */
private $order;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_invoice',
'primary' => 'id_order_invoice',
'fields' => array(
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'number' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'delivery_number' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'delivery_date' => array('type' => self::TYPE_DATE, 'validate' => 'isDateFormat'),
'total_discount_tax_excl' => array('type' => self::TYPE_FLOAT),
'total_discount_tax_incl' => array('type' => self::TYPE_FLOAT),
'total_paid_tax_excl' => array('type' => self::TYPE_FLOAT),
'total_paid_tax_incl' => array('type' => self::TYPE_FLOAT),
'total_products' => array('type' => self::TYPE_FLOAT),
'total_products_wt' => array('type' => self::TYPE_FLOAT),
'total_shipping_tax_excl' => array('type' => self::TYPE_FLOAT),
'total_shipping_tax_incl' => array('type' => self::TYPE_FLOAT),
'shipping_tax_computation_method' => array('type' => self::TYPE_INT),
'total_wrapping_tax_excl' => array('type' => self::TYPE_FLOAT),
'total_wrapping_tax_incl' => array('type' => self::TYPE_FLOAT),
'shop_address' => array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml', 'size' => 1000),
'note' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 65000),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
public function add($autodate = true, $null_values = false)
{
$order = new Order($this->id_order);
$this->shop_address = OrderInvoice::getCurrentFormattedShopAddress($order->id_shop);
return parent::add();
}
public function getProductsDetail()
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'order_detail` od
LEFT JOIN `' . _DB_PREFIX_ . 'product` p
ON p.id_product = od.product_id
LEFT JOIN `' . _DB_PREFIX_ . 'product_shop` ps ON (ps.id_product = p.id_product AND ps.id_shop = od.id_shop)
WHERE od.`id_order` = ' . (int) $this->id_order . '
' . ($this->id && $this->number ? ' AND od.`id_order_invoice` = ' . (int) $this->id : '') . ' ORDER BY od.`product_name`');
}
public static function getInvoiceByNumber($id_invoice)
{
if (is_numeric($id_invoice)) {
$id_invoice = (int) $id_invoice;
} elseif (is_string($id_invoice)) {
$matches = array();
if (preg_match('/^(?:' . Configuration::get('PS_INVOICE_PREFIX', Context::getContext()->language->id) . ')\s*([0-9]+)$/i', $id_invoice, $matches)) {
$id_invoice = $matches[1];
}
}
if (!$id_invoice) {
return false;
}
$id_order_invoice = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(
'SELECT `id_order_invoice`
FROM `' . _DB_PREFIX_ . 'order_invoice`
WHERE number = ' . (int) $id_invoice
);
return $id_order_invoice ? new OrderInvoice($id_order_invoice) : false;
}
/**
* Get order products.
*
* @return array Products with price, quantity (with taxe and without)
*/
public function getProducts($products = false, $selected_products = false, $selected_qty = false)
{
if (!$products) {
$products = $this->getProductsDetail();
}
$order = new Order($this->id_order);
$result_array = array();
foreach ($products as $row) {
// Change qty if selected
if ($selected_qty) {
$row['product_quantity'] = 0;
foreach ($selected_products as $key => $id_product) {
if ($row['id_order_detail'] == $id_product) {
$row['product_quantity'] = (int) $selected_qty[$key];
}
}
if (!$row['product_quantity']) {
continue;
}
}
$this->setProductImageInformations($row);
$this->setProductCurrentStock($row);
$customized_datas = Product::getAllCustomizedDatas($order->id_cart, null, true, null, (int) $row['id_customization']);
$this->setProductCustomizedDatas($row, $customized_datas);
// Add information for virtual product
if ($row['download_hash'] && !empty($row['download_hash'])) {
$row['filename'] = ProductDownload::getFilenameFromIdProduct((int) $row['product_id']);
// Get the display filename
$row['display_filename'] = ProductDownload::getFilenameFromFilename($row['filename']);
}
$row['id_address_delivery'] = $order->id_address_delivery;
/* Ecotax */
$round_mode = $order->round_mode;
$row['ecotax_tax_excl'] = $row['ecotax']; // alias for coherence
$row['ecotax_tax_incl'] = $row['ecotax'] * (100 + $row['ecotax_tax_rate']) / 100;
$row['ecotax_tax'] = $row['ecotax_tax_incl'] - $row['ecotax_tax_excl'];
if ($round_mode == Order::ROUND_ITEM) {
$row['ecotax_tax_incl'] = Tools::ps_round($row['ecotax_tax_incl'], _PS_PRICE_COMPUTE_PRECISION_, $round_mode);
}
$row['total_ecotax_tax_excl'] = $row['ecotax_tax_excl'] * $row['product_quantity'];
$row['total_ecotax_tax_incl'] = $row['ecotax_tax_incl'] * $row['product_quantity'];
$row['total_ecotax_tax'] = $row['total_ecotax_tax_incl'] - $row['total_ecotax_tax_excl'];
foreach (array(
'ecotax_tax_excl',
'ecotax_tax_incl',
'ecotax_tax',
'total_ecotax_tax_excl',
'total_ecotax_tax_incl',
'total_ecotax_tax',
) as $ecotax_field) {
$row[$ecotax_field] = Tools::ps_round($row[$ecotax_field], _PS_PRICE_COMPUTE_PRECISION_, $round_mode);
}
// Aliases
$row['unit_price_tax_excl_including_ecotax'] = $row['unit_price_tax_excl'];
$row['unit_price_tax_incl_including_ecotax'] = $row['unit_price_tax_incl'];
$row['total_price_tax_excl_including_ecotax'] = $row['total_price_tax_excl'];
$row['total_price_tax_incl_including_ecotax'] = $row['total_price_tax_incl'];
if ($customized_datas) {
Product::addProductCustomizationPrice($row, $customized_datas);
}
/* Stock product */
$result_array[(int) $row['id_order_detail']] = $row;
}
return $result_array;
}
protected function setProductCustomizedDatas(&$product, $customized_datas)
{
$product['customizedDatas'] = null;
if (isset($customized_datas[$product['product_id']][$product['product_attribute_id']])) {
$product['customizedDatas'] = $customized_datas[$product['product_id']][$product['product_attribute_id']];
} else {
$product['customizationQuantityTotal'] = 0;
}
}
/**
* This method allow to add stock information on a product detail.
*
* @param array &$product
*/
protected function setProductCurrentStock(&$product)
{
if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT')
&& (int) $product['advanced_stock_management'] == 1
&& (int) $product['id_warehouse'] > 0) {
$product['current_stock'] = StockManagerFactory::getManager()->getProductPhysicalQuantities($product['product_id'], $product['product_attribute_id'], null, true);
} else {
$product['current_stock'] = '--';
}
}
/**
* This method allow to add image information on a product detail.
*
* @param array &$product
*/
protected function setProductImageInformations(&$product)
{
if (isset($product['product_attribute_id']) && $product['product_attribute_id']) {
$id_image = Db::getInstance()->getValue('
SELECT image_shop.id_image
FROM ' . _DB_PREFIX_ . 'product_attribute_image pai' .
Shop::addSqlAssociation('image', 'pai', true) . '
WHERE id_product_attribute = ' . (int) $product['product_attribute_id']);
}
if (!isset($id_image) || !$id_image) {
$id_image = Db::getInstance()->getValue('
SELECT image_shop.id_image
FROM ' . _DB_PREFIX_ . 'image i' .
Shop::addSqlAssociation('image', 'i', true, 'image_shop.cover=1') . '
WHERE i.id_product = ' . (int) $product['product_id']);
}
$product['image'] = null;
$product['image_size'] = null;
if ($id_image) {
$product['image'] = new Image($id_image);
}
}
/**
* This method returns true if at least one order details uses the
* One After Another tax computation method.
*
* @since 1.5
*
* @return bool
*/
public function useOneAfterAnotherTaxComputationMethod()
{
// if one of the order details use the tax computation method the display will be different
return Db::getInstance()->getValue('
SELECT od.`tax_computation_method`
FROM `' . _DB_PREFIX_ . 'order_detail_tax` odt
LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` od ON (od.`id_order_detail` = odt.`id_order_detail`)
WHERE od.`id_order` = ' . (int) $this->id_order . '
AND od.`id_order_invoice` = ' . (int) $this->id . '
AND od.`tax_computation_method` = ' . (int) TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
|| Configuration::get(
'PS_INVOICE_TAXES_BREAKDOWN'
);
}
public function displayTaxBasesInProductTaxesBreakdown()
{
return !$this->useOneAfterAnotherTaxComputationMethod();
}
public function getOrder()
{
if (!$this->order) {
$this->order = new Order($this->id_order);
}
return $this->order;
}
public function getProductTaxesBreakdown($order = null)
{
if (!$order) {
$order = $this->getOrder();
}
$sum_composite_taxes = !$this->useOneAfterAnotherTaxComputationMethod();
// $breakdown will be an array with tax rates as keys and at least the columns:
// - 'total_price_tax_excl'
// - 'total_amount'
$breakdown = array();
$details = $order->getProductTaxesDetails();
if ($sum_composite_taxes) {
$grouped_details = array();
foreach ($details as $row) {
if (!isset($grouped_details[$row['id_order_detail']])) {
$grouped_details[$row['id_order_detail']] = array(
'tax_rate' => 0,
'total_tax_base' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
);
}
$grouped_details[$row['id_order_detail']]['tax_rate'] += $row['tax_rate'];
$grouped_details[$row['id_order_detail']]['total_tax_base'] += $row['total_tax_base'];
$grouped_details[$row['id_order_detail']]['total_amount'] += $row['total_amount'];
}
$details = $grouped_details;
}
foreach ($details as $row) {
$rate = sprintf('%.3f', $row['tax_rate']);
if (!isset($breakdown[$rate])) {
$breakdown[$rate] = array(
'total_price_tax_excl' => 0,
'total_amount' => 0,
'id_tax' => $row['id_tax'],
'rate' => $rate,
);
}
$breakdown[$rate]['total_price_tax_excl'] += $row['total_tax_base'];
$breakdown[$rate]['total_amount'] += $row['total_amount'];
}
foreach ($breakdown as $rate => $data) {
$breakdown[$rate]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
$breakdown[$rate]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $order->round_mode);
}
ksort($breakdown);
return $breakdown;
}
/**
* Returns the shipping taxes breakdown.
*
* @since 1.5
*
* @param Order $order
*
* @return array
*/
public function getShippingTaxesBreakdown($order)
{
// No shipping breakdown if no shipping!
if ($this->total_shipping_tax_excl == 0) {
return array();
}
// No shipping breakdown if it's free!
foreach ($order->getCartRules() as $cart_rule) {
if ($cart_rule['free_shipping']) {
return array();
}
}
$shipping_tax_amount = $this->total_shipping_tax_incl - $this->total_shipping_tax_excl;
if (Configuration::get('PS_INVOICE_TAXES_BREAKDOWN') || Configuration::get('PS_ATCP_SHIPWRAP')) {
$shipping_breakdown = Db::getInstance()->executeS(
'SELECT t.id_tax, t.rate, oit.amount as total_amount
FROM `' . _DB_PREFIX_ . 'tax` t
INNER JOIN `' . _DB_PREFIX_ . 'order_invoice_tax` oit ON oit.id_tax = t.id_tax
WHERE oit.type = "shipping" AND oit.id_order_invoice = ' . (int) $this->id
);
$sum_of_split_taxes = 0;
$sum_of_tax_bases = 0;
foreach ($shipping_breakdown as &$row) {
if (Configuration::get('PS_ATCP_SHIPWRAP')) {
$row['total_tax_excl'] = Tools::ps_round($row['total_amount'] / $row['rate'] * 100, _PS_PRICE_COMPUTE_PRECISION_, $this->getOrder()->round_mode);
$sum_of_tax_bases += $row['total_tax_excl'];
} else {
$row['total_tax_excl'] = $this->total_shipping_tax_excl;
}
$row['total_amount'] = Tools::ps_round($row['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $this->getOrder()->round_mode);
$sum_of_split_taxes += $row['total_amount'];
}
unset($row);
$delta_amount = $shipping_tax_amount - $sum_of_split_taxes;
if ($delta_amount != 0) {
Tools::spreadAmount($delta_amount, _PS_PRICE_COMPUTE_PRECISION_, $shipping_breakdown, 'total_amount');
}
$delta_base = $this->total_shipping_tax_excl - $sum_of_tax_bases;
if ($delta_base != 0) {
Tools::spreadAmount($delta_base, _PS_PRICE_COMPUTE_PRECISION_, $shipping_breakdown, 'total_tax_excl');
}
} else {
$shipping_breakdown = array(
array(
'total_tax_excl' => $this->total_shipping_tax_excl,
'rate' => $order->carrier_tax_rate,
'total_amount' => $shipping_tax_amount,
'id_tax' => null,
),
);
}
return $shipping_breakdown;
}
/**
* Returns the wrapping taxes breakdown.
*
* @return array
*/
public function getWrappingTaxesBreakdown()
{
if ($this->total_wrapping_tax_excl == 0) {
return array();
}
$wrapping_tax_amount = $this->total_wrapping_tax_incl - $this->total_wrapping_tax_excl;
$wrapping_breakdown = Db::getInstance()->executeS(
'SELECT t.id_tax, t.rate, oit.amount as total_amount
FROM `' . _DB_PREFIX_ . 'tax` t
INNER JOIN `' . _DB_PREFIX_ . 'order_invoice_tax` oit ON oit.id_tax = t.id_tax
WHERE oit.type = "wrapping" AND oit.id_order_invoice = ' . (int) $this->id
);
$sum_of_split_taxes = 0;
$sum_of_tax_bases = 0;
$total_tax_rate = 0;
foreach ($wrapping_breakdown as &$row) {
if (Configuration::get('PS_ATCP_SHIPWRAP')) {
$row['total_tax_excl'] = Tools::ps_round($row['total_amount'] / $row['rate'] * 100, _PS_PRICE_COMPUTE_PRECISION_, $this->getOrder()->round_mode);
$sum_of_tax_bases += $row['total_tax_excl'];
} else {
$row['total_tax_excl'] = $this->total_wrapping_tax_excl;
}
$row['total_amount'] = Tools::ps_round($row['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $this->getOrder()->round_mode);
$sum_of_split_taxes += $row['total_amount'];
$total_tax_rate += (float) $row['rate'];
}
unset($row);
$delta_amount = $wrapping_tax_amount - $sum_of_split_taxes;
if ($delta_amount != 0) {
Tools::spreadAmount($delta_amount, _PS_PRICE_COMPUTE_PRECISION_, $wrapping_breakdown, 'total_amount');
}
$delta_base = $this->total_wrapping_tax_excl - $sum_of_tax_bases;
if ($delta_base != 0) {
Tools::spreadAmount($delta_base, _PS_PRICE_COMPUTE_PRECISION_, $wrapping_breakdown, 'total_tax_excl');
}
if (!Configuration::get('PS_INVOICE_TAXES_BREAKDOWN') && !Configuration::get('PS_ATCP_SHIPWRAP')) {
$wrapping_breakdown = array(
array(
'total_tax_excl' => $this->total_wrapping_tax_excl,
'rate' => $total_tax_rate,
'total_amount' => $wrapping_tax_amount,
),
);
}
return $wrapping_breakdown;
}
/**
* Returns the ecotax taxes breakdown.
*
* @since 1.5
*
* @return array
*/
public function getEcoTaxTaxesBreakdown()
{
$result = Db::getInstance()->executeS('
SELECT `ecotax_tax_rate` as `rate`, SUM(`ecotax` * `product_quantity`) as `ecotax_tax_excl`, SUM(`ecotax` * `product_quantity`) as `ecotax_tax_incl`
FROM `' . _DB_PREFIX_ . 'order_detail`
WHERE `id_order` = ' . (int) $this->id_order . '
AND `id_order_invoice` = ' . (int) $this->id . '
GROUP BY `ecotax_tax_rate`');
$taxes = array();
foreach ($result as $row) {
if ($row['ecotax_tax_excl'] > 0) {
$row['ecotax_tax_incl'] = Tools::ps_round($row['ecotax_tax_excl'] + ($row['ecotax_tax_excl'] * $row['rate'] / 100), _PS_PRICE_DISPLAY_PRECISION_);
$row['ecotax_tax_excl'] = Tools::ps_round($row['ecotax_tax_excl'], _PS_PRICE_DISPLAY_PRECISION_);
$taxes[] = $row;
}
}
return $taxes;
}
/**
* Returns all the order invoice that match the date interval.
*
* @since 1.5
*
* @param $date_from
* @param $date_to
*
* @return array collection of OrderInvoice
*/
public static function getByDateInterval($date_from, $date_to)
{
$order_invoice_list = Db::getInstance()->executeS('
SELECT oi.*
FROM `' . _DB_PREFIX_ . 'order_invoice` oi
LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON (o.`id_order` = oi.`id_order`)
WHERE DATE_ADD(oi.date_add, INTERVAL -1 DAY) <= \'' . pSQL($date_to) . '\'
AND oi.date_add >= \'' . pSQL($date_from) . '\'
' . Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o') . '
AND oi.number > 0
ORDER BY oi.date_add ASC
');
return ObjectModel::hydrateCollection('OrderInvoice', $order_invoice_list);
}
/**
* @since 1.5.0.3
*
* @param $id_order_state
*
* @return array collection of OrderInvoice
*/
public static function getByStatus($id_order_state)
{
$order_invoice_list = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT oi.*
FROM `' . _DB_PREFIX_ . 'order_invoice` oi
LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON (o.`id_order` = oi.`id_order`)
WHERE ' . (int) $id_order_state . ' = o.current_state
' . Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o') . '
AND oi.number > 0
ORDER BY oi.`date_add` ASC
');
return ObjectModel::hydrateCollection('OrderInvoice', $order_invoice_list);
}
/**
* @since 1.5.0.3
*
* @param $date_from
* @param $date_to
*
* @return array collection of invoice
*/
public static function getByDeliveryDateInterval($date_from, $date_to)
{
$order_invoice_list = Db::getInstance()->executeS('
SELECT oi.*
FROM `' . _DB_PREFIX_ . 'order_invoice` oi
LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON (o.`id_order` = oi.`id_order`)
WHERE DATE_ADD(oi.delivery_date, INTERVAL -1 DAY) <= \'' . pSQL($date_to) . '\'
AND oi.delivery_date >= \'' . pSQL($date_from) . '\'
' . Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o') . '
ORDER BY oi.delivery_date ASC
');
return ObjectModel::hydrateCollection('OrderInvoice', $order_invoice_list);
}
/**
* @since 1.5
*
* @param $id_order_invoice
*/
public static function getCarrier($id_order_invoice)
{
$carrier = false;
if ($id_carrier = OrderInvoice::getCarrierId($id_order_invoice)) {
$carrier = new Carrier((int) $id_carrier);
}
return $carrier;
}
/**
* @since 1.5
*
* @param $id_order_invoice
*/
public static function getCarrierId($id_order_invoice)
{
$sql = 'SELECT `id_carrier`
FROM `' . _DB_PREFIX_ . 'order_carrier`
WHERE `id_order_invoice` = ' . (int) $id_order_invoice;
return Db::getInstance()->getValue($sql);
}
/**
* @param int $id
*
* @return OrderInvoice
*
* @throws PrestaShopException
*/
public static function retrieveOneById($id)
{
$order_invoice = new OrderInvoice($id);
if (!Validate::isLoadedObject($order_invoice)) {
throw new PrestaShopException('Can\'t load Order Invoice object for id: ' . $id);
}
return $order_invoice;
}
/**
* Amounts of payments.
*
* @since 1.5.0.2
*
* @return float Total paid
*/
public function getTotalPaid()
{
$cache_id = 'order_invoice_paid_' . (int) $this->id;
if (!Cache::isStored($cache_id)) {
$amount = 0;
$payments = OrderPayment::getByInvoiceId($this->id);
foreach ($payments as $payment) {
/* @var OrderPayment $payment */
$amount += $payment->amount;
}
Cache::store($cache_id, $amount);
return $amount;
}
return Cache::retrieve($cache_id);
}
/**
* Rest Paid.
*
* @since 1.5.0.2
*
* @return float Rest Paid
*/
public function getRestPaid()
{
return round($this->total_paid_tax_incl + $this->getSiblingTotal() - $this->getTotalPaid(), 2);
}
/**
* Return collection of order invoice object linked to the payments of the current order invoice object.
*
* @since 1.5.0.14
*
* @return PrestaShopCollection|array Collection of OrderInvoice or empty array
*/
public function getSibling()
{
$query = new DbQuery();
$query->select('oip2.id_order_invoice');
$query->from('order_invoice_payment', 'oip1');
$query->innerJoin(
'order_invoice_payment',
'oip2',
'oip2.id_order_payment = oip1.id_order_payment
AND oip2.id_order_invoice <> oip1.id_order_invoice
AND oip2.id_order = oip1.id_order'
);
$query->where('oip1.id_order_invoice = ' . (int) $this->id);
$invoices = Db::getInstance()->executeS($query);
if (!$invoices) {
return array();
}
$invoice_list = array();
foreach ($invoices as $invoice) {
$invoice_list[] = $invoice['id_order_invoice'];
}
$payments = new PrestaShopCollection('OrderInvoice');
$payments->where('id_order_invoice', 'IN', $invoice_list);
return $payments;
}
/**
* Return total to paid of sibling invoices.
*
* @param int $mod TAX_EXCL, TAX_INCL, DETAIL
*
* @since 1.5.0.14
*/
public function getSiblingTotal($mod = OrderInvoice::TAX_INCL)
{
$query = new DbQuery();
$query->select('SUM(oi.total_paid_tax_incl) as total_paid_tax_incl, SUM(oi.total_paid_tax_excl) as total_paid_tax_excl');
$query->from('order_invoice_payment', 'oip1');
$query->innerJoin(
'order_invoice_payment',
'oip2',
'oip2.id_order_payment = oip1.id_order_payment
AND oip2.id_order_invoice <> oip1.id_order_invoice
AND oip2.id_order = oip1.id_order'
);
$query->leftJoin(
'order_invoice',
'oi',
'oi.id_order_invoice = oip2.id_order_invoice'
);
$query->where('oip1.id_order_invoice = ' . (int) $this->id);
$row = Db::getInstance()->getRow($query);
switch ($mod) {
case OrderInvoice::TAX_EXCL:
return $row['total_paid_tax_excl'];
case OrderInvoice::TAX_INCL:
return $row['total_paid_tax_incl'];
default:
return $row;
}
}
/**
* Get global rest to paid
* This method will return something different of the method getRestPaid if
* there is an other invoice linked to the payments of the current invoice.
*
* @since 1.5.0.13
*/
public function getGlobalRestPaid()
{
static $cache;
if (!isset($cache[$this->id])) {
$res = Db::getInstance()->getRow('
SELECT SUM(sub.paid) paid, SUM(sub.to_paid) to_paid
FROM (
SELECT
op.amount as paid, SUM(oi.total_paid_tax_incl) to_paid
FROM `' . _DB_PREFIX_ . 'order_invoice_payment` oip1
INNER JOIN `' . _DB_PREFIX_ . 'order_invoice_payment` oip2
ON oip2.id_order_payment = oip1.id_order_payment
INNER JOIN `' . _DB_PREFIX_ . 'order_invoice` oi
ON oi.id_order_invoice = oip2.id_order_invoice
INNER JOIN `' . _DB_PREFIX_ . 'order_payment` op
ON op.id_order_payment = oip2.id_order_payment
WHERE oip1.id_order_invoice = ' . (int) $this->id . '
GROUP BY op.id_order_payment
) sub');
$cache[$this->id] = round($res['to_paid'] - $res['paid'], 2);
}
return $cache[$this->id];
}
/**
* @since 1.5.0.2
*
* @return bool Is paid ?
*/
public function isPaid()
{
return $this->getTotalPaid() == $this->total_paid_tax_incl;
}
/**
* @since 1.5.0.2
*
* @return PrestaShopCollection Collection of Order payment
*/
public function getOrderPaymentCollection()
{
return OrderPayment::getByInvoiceId($this->id);
}
/**
* Get the formatted number of invoice.
*
* @since 1.5.0.2
*
* @param int $id_lang for invoice_prefix
*
* @return string
*/
public function getInvoiceNumberFormatted($id_lang, $id_shop = null)
{
$invoice_formatted_number = Hook::exec('actionInvoiceNumberFormatted', array(
get_class($this) => $this,
'id_lang' => (int) $id_lang,
'id_shop' => (int) $id_shop,
'number' => (int) $this->number,
));
if (!empty($invoice_formatted_number)) {
return $invoice_formatted_number;
}
$format = '%1$s%2$06d';
if (Configuration::get('PS_INVOICE_USE_YEAR')) {
$format = Configuration::get('PS_INVOICE_YEAR_POS') ? '%1$s%3$s/%2$06d' : '%1$s%2$06d/%3$s';
}
return sprintf($format, Configuration::get('PS_INVOICE_PREFIX', (int) $id_lang, null, (int) $id_shop), $this->number, date('Y', strtotime($this->date_add)));
}
public function saveCarrierTaxCalculator(array $taxes_amount)
{
$is_correct = true;
foreach ($taxes_amount as $id_tax => $amount) {
$sql = 'INSERT INTO `' . _DB_PREFIX_ . 'order_invoice_tax` (`id_order_invoice`, `type`, `id_tax`, `amount`)
VALUES (' . (int) $this->id . ', \'shipping\', ' . (int) $id_tax . ', ' . (float) $amount . ')';
$is_correct &= Db::getInstance()->execute($sql);
}
return $is_correct;
}
public function saveWrappingTaxCalculator(array $taxes_amount)
{
$is_correct = true;
foreach ($taxes_amount as $id_tax => $amount) {
$sql = 'INSERT INTO `' . _DB_PREFIX_ . 'order_invoice_tax` (`id_order_invoice`, `type`, `id_tax`, `amount`)
VALUES (' . (int) $this->id . ', \'wrapping\', ' . (int) $id_tax . ', ' . (float) $amount . ')';
$is_correct &= Db::getInstance()->execute($sql);
}
return $is_correct;
}
public static function getCurrentFormattedShopAddress($id_shop = null)
{
$address = new Address();
$address->company = Configuration::get('PS_SHOP_NAME', null, null, $id_shop);
$address->address1 = Configuration::get('PS_SHOP_ADDR1', null, null, $id_shop);
$address->address2 = Configuration::get('PS_SHOP_ADDR2', null, null, $id_shop);
$address->postcode = Configuration::get('PS_SHOP_CODE', null, null, $id_shop);
$address->city = Configuration::get('PS_SHOP_CITY', null, null, $id_shop);
$address->phone = Configuration::get('PS_SHOP_PHONE', null, null, $id_shop);
$address->id_country = Configuration::get('PS_SHOP_COUNTRY_ID', null, null, $id_shop);
return AddressFormat::generateAddress($address, array(), '<br />', ' ');
}
/**
* This method is used to fix shop addresses that cannot be fixed during upgrade process
* (because uses the whole environnement of PS classes that is not available during upgrade).
* This method should execute once on an upgraded PrestaShop to fix all OrderInvoices in one shot.
* This method is triggered once during a (non bulk) creation of a PDF from an OrderInvoice that is not fixed yet.
*
* @since 1.6.1.1
*/
public static function fixAllShopAddresses()
{
$shop_ids = Shop::getShops(false, null, true);
$db = Db::getInstance();
foreach ($shop_ids as $id_shop) {
$address = OrderInvoice::getCurrentFormattedShopAddress($id_shop);
$escaped_address = $db->escape($address, true, true);
$db->execute('UPDATE `' . _DB_PREFIX_ . 'order_invoice` INNER JOIN `' . _DB_PREFIX_ . 'orders` USING (`id_order`)
SET `shop_address` = \'' . $escaped_address . '\' WHERE `shop_address` IS NULL AND `id_shop` = ' . $id_shop);
}
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderMessageCore extends ObjectModel
{
/** @var string name name */
public $name;
/** @var string message content */
public $message;
/** @var string Object creation date */
public $date_add;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_message',
'primary' => 'id_order_message',
'multilang' => true,
'fields' => array(
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
/* Lang fields */
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 128),
'message' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isMessage', 'required' => true, 'size' => 1200),
),
);
protected $webserviceParameters = array(
'fields' => array(
'id' => array('sqlId' => 'id_discount_type', 'xlink_resource' => 'order_message_lang'),
'date_add' => array('sqlId' => 'date_add'),
),
);
public static function getOrderMessages($id_lang)
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT om.id_order_message, oml.name, oml.message
FROM ' . _DB_PREFIX_ . 'order_message om
LEFT JOIN ' . _DB_PREFIX_ . 'order_message_lang oml ON (oml.id_order_message = om.id_order_message)
WHERE oml.id_lang = ' . (int) $id_lang . '
ORDER BY name ASC');
}
}

View File

@@ -0,0 +1,156 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderPaymentCore extends ObjectModel
{
public $order_reference;
public $id_currency;
public $amount;
public $payment_method;
public $conversion_rate;
public $transaction_id;
public $card_number;
public $card_brand;
public $card_expiration;
public $card_holder;
public $date_add;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_payment',
'primary' => 'id_order_payment',
'fields' => array(
'order_reference' => array('type' => self::TYPE_STRING, 'validate' => 'isAnything', 'size' => 9),
'id_currency' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isNegativePrice', 'required' => true),
'payment_method' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'conversion_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'transaction_id' => array('type' => self::TYPE_STRING, 'validate' => 'isAnything', 'size' => 254),
'card_number' => array('type' => self::TYPE_STRING, 'validate' => 'isAnything', 'size' => 254),
'card_brand' => array('type' => self::TYPE_STRING, 'validate' => 'isAnything', 'size' => 254),
'card_expiration' => array('type' => self::TYPE_STRING, 'validate' => 'isAnything', 'size' => 254),
'card_holder' => array('type' => self::TYPE_STRING, 'validate' => 'isAnything', 'size' => 254),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
public function add($autodate = true, $nullValues = false)
{
if (parent::add($autodate, $nullValues)) {
Hook::exec('actionPaymentCCAdd', array('paymentCC' => $this));
return true;
}
return false;
}
/**
* Get the detailed payment of an order.
*
* @deprecated 1.5.3.0
*
* @param int $id_order
*
* @return array
*/
public static function getByOrderId($id_order)
{
Tools::displayAsDeprecated();
$order = new Order($id_order);
return OrderPayment::getByOrderReference($order->reference);
}
/**
* Get the detailed payment of an order.
*
* @param int $order_reference
*
* @return array
*
* @since 1.5.0.13
*/
public static function getByOrderReference($order_reference)
{
return ObjectModel::hydrateCollection(
'OrderPayment',
Db::getInstance()->executeS(
'SELECT *
FROM `' . _DB_PREFIX_ . 'order_payment`
WHERE `order_reference` = \'' . pSQL($order_reference) . '\''
)
);
}
/**
* Get Order Payments By Invoice ID.
*
* @param int $id_invoice Invoice ID
*
* @return PrestaShopCollection Collection of OrderPayment
*/
public static function getByInvoiceId($id_invoice)
{
$payments = Db::getInstance()->executeS('SELECT id_order_payment FROM `' . _DB_PREFIX_ . 'order_invoice_payment` WHERE id_order_invoice = ' . (int) $id_invoice);
if (!$payments) {
return array();
}
$payment_list = array();
foreach ($payments as $payment) {
$payment_list[] = $payment['id_order_payment'];
}
$payments = new PrestaShopCollection('OrderPayment');
$payments->where('id_order_payment', 'IN', $payment_list);
return $payments;
}
/**
* Return order invoice object linked to the payment.
*
* @param int $id_order Order Id
*
* @since 1.5.0.13
*/
public function getOrderInvoice($id_order)
{
$res = Db::getInstance()->getValue('
SELECT id_order_invoice
FROM `' . _DB_PREFIX_ . 'order_invoice_payment`
WHERE id_order_payment = ' . (int) $this->id . '
AND id_order = ' . (int) $id_order);
if (!$res) {
return false;
}
return new OrderInvoice((int) $res);
}
}

View File

@@ -0,0 +1,276 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderReturnCore extends ObjectModel
{
/** @var int */
public $id;
/** @var int */
public $id_customer;
/** @var int */
public $id_order;
/** @var int */
public $state;
/** @var string message content */
public $question;
/** @var string Object creation date */
public $date_add;
/** @var string Object last modification date */
public $date_upd;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_return',
'primary' => 'id_order_return',
'fields' => array(
'id_customer' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'question' => array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml'),
'state' => array('type' => self::TYPE_STRING),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
),
);
public function addReturnDetail($order_detail_list, $product_qty_list, $customization_ids, $customization_qty_input)
{
/* Classic product return */
if ($order_detail_list) {
foreach ($order_detail_list as $key => $order_detail) {
if ($qty = (int) $product_qty_list[$key]) {
Db::getInstance()->insert('order_return_detail', array('id_order_return' => (int) $this->id, 'id_order_detail' => (int) $order_detail, 'product_quantity' => $qty, 'id_customization' => 0));
}
}
}
/* Customized product return */
if ($customization_ids) {
foreach ($customization_ids as $order_detail_id => $customizations) {
foreach ($customizations as $customization_id) {
if ($quantity = (int) $customization_qty_input[(int) $customization_id]) {
Db::getInstance()->insert('order_return_detail', array('id_order_return' => (int) $this->id, 'id_order_detail' => (int) $order_detail_id, 'product_quantity' => $quantity, 'id_customization' => (int) $customization_id));
}
}
}
}
}
public function checkEnoughProduct($order_detail_list, $product_qty_list, $customization_ids, $customization_qty_input)
{
$order = new Order((int) $this->id_order);
if (!Validate::isLoadedObject($order)) {
die(Tools::displayError());
}
$products = $order->getProducts();
/* Products already returned */
$order_return = OrderReturn::getOrdersReturn($order->id_customer, $order->id, true);
foreach ($order_return as $or) {
$order_return_products = OrderReturn::getOrdersReturnProducts($or['id_order_return'], $order);
foreach ($order_return_products as $key => $orp) {
$products[$key]['product_quantity'] -= (int) $orp['product_quantity'];
}
}
/* Quantity check */
if ($order_detail_list) {
foreach (array_keys($order_detail_list) as $key) {
if ($qty = (int) $product_qty_list[$key]) {
if ($products[$key]['product_quantity'] - $qty < 0) {
return false;
}
}
}
}
/* Customization quantity check */
if ($customization_ids) {
$ordered_customizations = Customization::getOrderedCustomizations((int) $order->id_cart);
foreach ($customization_ids as $customizations) {
foreach ($customizations as $customization_id) {
$customization_id = (int) $customization_id;
if (!isset($ordered_customizations[$customization_id])) {
return false;
}
$quantity = (isset($customization_qty_input[$customization_id]) ? (int) $customization_qty_input[$customization_id] : 0);
if ((int) $ordered_customizations[$customization_id]['quantity'] - $quantity < 0) {
return false;
}
}
}
}
return true;
}
public function countProduct()
{
if (!$data = Db::getInstance()->getRow('
SELECT COUNT(`id_order_return`) AS total
FROM `' . _DB_PREFIX_ . 'order_return_detail`
WHERE `id_order_return` = ' . (int) $this->id)) {
return false;
}
return (int) ($data['total']);
}
public static function getOrdersReturn($customer_id, $order_id = false, $no_denied = false, Context $context = null)
{
if (!$context) {
$context = Context::getContext();
}
$data = Db::getInstance()->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'order_return`
WHERE `id_customer` = ' . (int) $customer_id .
($order_id ? ' AND `id_order` = ' . (int) $order_id : '') .
($no_denied ? ' AND `state` != 4' : '') . '
ORDER BY `date_add` DESC');
foreach ($data as $k => $or) {
$state = new OrderReturnState($or['state']);
$data[$k]['state_name'] = $state->name[$context->language->id];
$data[$k]['type'] = 'Return';
$data[$k]['tracking_number'] = $or['id_order_return'];
$data[$k]['can_edit'] = false;
$data[$k]['reference'] = Order::getUniqReferenceOf($or['id_order']);
}
return $data;
}
public static function getOrdersReturnDetail($id_order_return)
{
return Db::getInstance()->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'order_return_detail`
WHERE `id_order_return` = ' . (int) $id_order_return);
}
/**
* @param int $order_return_id
* @param Order $order
*
* @return array
*/
public static function getOrdersReturnProducts($order_return_id, $order)
{
$products_ret = OrderReturn::getOrdersReturnDetail($order_return_id);
$products = $order->getProducts();
$tmp = array();
foreach ($products_ret as $return_detail) {
$tmp[$return_detail['id_order_detail']]['quantity'] = isset($tmp[$return_detail['id_order_detail']]['quantity']) ? $tmp[$return_detail['id_order_detail']]['quantity'] + (int) $return_detail['product_quantity'] : (int) $return_detail['product_quantity'];
$tmp[$return_detail['id_order_detail']]['customizations'] = (int) $return_detail['id_customization'];
}
$res_tab = array();
foreach ($products as $key => $product) {
if (isset($tmp[$product['id_order_detail']])) {
$res_tab[$key] = $product;
$res_tab[$key]['product_quantity'] = $tmp[$product['id_order_detail']]['quantity'];
$res_tab[$key]['customizations'] = $tmp[$product['id_order_detail']]['customizations'];
}
}
return $res_tab;
}
public static function getReturnedCustomizedProducts($id_order)
{
$returns = Customization::getReturnedCustomizations($id_order);
$order = new Order((int) $id_order);
if (!Validate::isLoadedObject($order)) {
die(Tools::displayError());
}
$products = $order->getProducts();
foreach ($returns as &$return) {
$return['product_id'] = (int) $products[(int) $return['id_order_detail']]['product_id'];
$return['product_attribute_id'] = (int) $products[(int) $return['id_order_detail']]['product_attribute_id'];
$return['name'] = $products[(int) $return['id_order_detail']]['product_name'];
$return['reference'] = $products[(int) $return['id_order_detail']]['product_reference'];
$return['id_address_delivery'] = $products[(int) $return['id_order_detail']]['id_address_delivery'];
}
return $returns;
}
public static function deleteOrderReturnDetail($id_order_return, $id_order_detail, $id_customization = 0)
{
return Db::getInstance()->execute('DELETE FROM `' . _DB_PREFIX_ . 'order_return_detail` WHERE `id_order_detail` = ' . (int) $id_order_detail . ' AND `id_order_return` = ' . (int) $id_order_return . ' AND `id_customization` = ' . (int) $id_customization);
}
/**
* Get return details for one product line.
*
* @param $id_order_detail
*/
public static function getProductReturnDetail($id_order_detail)
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT product_quantity, date_add, orsl.name as state
FROM `' . _DB_PREFIX_ . 'order_return_detail` ord
LEFT JOIN `' . _DB_PREFIX_ . 'order_return` o
ON o.id_order_return = ord.id_order_return
LEFT JOIN `' . _DB_PREFIX_ . 'order_return_state_lang` orsl
ON orsl.id_order_return_state = o.state AND orsl.id_lang = ' . (int) Context::getContext()->language->id . '
WHERE ord.`id_order_detail` = ' . (int) $id_order_detail);
}
/**
* Add returned quantity to products list.
*
* @param array $products
* @param int $id_order
*/
public static function addReturnedQuantity(&$products, $id_order)
{
$details = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
'SELECT od.id_order_detail, GREATEST(od.product_quantity_return, IFNULL(SUM(ord.product_quantity),0)) as qty_returned
FROM ' . _DB_PREFIX_ . 'order_detail od
LEFT JOIN ' . _DB_PREFIX_ . 'order_return_detail ord
ON ord.id_order_detail = od.id_order_detail
WHERE od.id_order = ' . (int) $id_order . '
GROUP BY od.id_order_detail'
);
if (!$details) {
return;
}
$detail_list = array();
foreach ($details as $detail) {
$detail_list[$detail['id_order_detail']] = $detail;
}
foreach ($products as &$product) {
if (isset($detail_list[$product['id_order_detail']]['qty_returned'])) {
$product['qty_returned'] = $detail_list[$product['id_order_detail']]['qty_returned'];
}
}
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderReturnStateCore extends ObjectModel
{
/** @var string Name */
public $name;
/** @var string Display state in the specified color */
public $color;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_return_state',
'primary' => 'id_order_return_state',
'multilang' => true,
'fields' => array(
'color' => array('type' => self::TYPE_STRING, 'validate' => 'isColor'),
/* Lang fields */
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
),
);
/**
* Get all available order statuses.
*
* @param int $id_lang Language id for status name
*
* @return array Order statuses
*/
public static function getOrderReturnStates($id_lang)
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'order_return_state` ors
LEFT JOIN `' . _DB_PREFIX_ . 'order_return_state_lang` orsl ON (ors.`id_order_return_state` = orsl.`id_order_return_state` AND orsl.`id_lang` = ' . (int) $id_lang . ')
ORDER BY ors.`id_order_return_state` ASC');
}
}

550
classes/order/OrderSlip.php Normal file
View File

@@ -0,0 +1,550 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderSlipCore extends ObjectModel
{
/** @var int */
public $id;
/** @var int */
public $id_customer;
/** @var int */
public $id_order;
/** @var float */
public $conversion_rate;
/** @var float */
public $total_products_tax_excl;
/** @var float */
public $total_products_tax_incl;
/** @var float */
public $total_shipping_tax_excl;
/** @var float */
public $total_shipping_tax_incl;
/** @var int */
public $amount;
/** @var int */
public $shipping_cost;
/** @var int */
public $shipping_cost_amount;
/** @var int */
public $partial;
/** @var string Object creation date */
public $date_add;
/** @var string Object last modification date */
public $date_upd;
/** @var int */
public $order_slip_type = 0;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_slip',
'primary' => 'id_order_slip',
'fields' => array(
'id_customer' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'id_order' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'conversion_rate' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'total_products_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'total_products_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'total_shipping_tax_excl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'total_shipping_tax_incl' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'required' => true),
'amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'shipping_cost' => array('type' => self::TYPE_INT),
'shipping_cost_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'),
'partial' => array('type' => self::TYPE_INT),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
'order_slip_type' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
),
);
protected $webserviceParameters = array(
'objectNodeName' => 'order_slip',
'objectsNodeName' => 'order_slips',
'fields' => array(
'id_customer' => array('xlink_resource' => 'customers'),
'id_order' => array('xlink_resource' => 'orders'),
),
'associations' => array(
'order_slip_details' => array('resource' => 'order_slip_detail', 'setter' => false, 'virtual_entity' => true,
'fields' => array(
'id' => array(),
'id_order_detail' => array('required' => true),
'product_quantity' => array('required' => true),
'amount_tax_excl' => array('required' => true),
'amount_tax_incl' => array('required' => true),
), ),
),
);
public function addSlipDetail($orderDetailList, $productQtyList)
{
foreach ($orderDetailList as $key => $id_order_detail) {
if ($qty = (int) ($productQtyList[$key])) {
$order_detail = new OrderDetail((int) $id_order_detail);
if (Validate::isLoadedObject($order_detail)) {
Db::getInstance()->insert('order_slip_detail', array(
'id_order_slip' => (int) $this->id,
'id_order_detail' => (int) $id_order_detail,
'product_quantity' => $qty,
'amount_tax_excl' => $order_detail->unit_price_tax_excl * $qty,
'amount_tax_incl' => $order_detail->unit_price_tax_incl * $qty,
));
}
}
}
}
public static function getOrdersSlip($customer_id, $order_id = false)
{
return Db::getInstance()->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'order_slip`
WHERE `id_customer` = ' . (int) ($customer_id) .
($order_id ? ' AND `id_order` = ' . (int) ($order_id) : '') . '
ORDER BY `date_add` DESC');
}
public static function getOrdersSlipDetail($id_order_slip = false, $id_order_detail = false)
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
($id_order_detail ? 'SELECT SUM(`product_quantity`) AS `total`' : 'SELECT *') .
'FROM `' . _DB_PREFIX_ . 'order_slip_detail`'
. ($id_order_slip ? ' WHERE `id_order_slip` = ' . (int) ($id_order_slip) : '')
. ($id_order_detail ? ' WHERE `id_order_detail` = ' . (int) ($id_order_detail) : '')
);
}
/**
* @param int $orderSlipId
* @param Order $order
*
* @return array
*/
public static function getOrdersSlipProducts($orderSlipId, $order)
{
$productsRet = OrderSlip::getOrdersSlipDetail($orderSlipId);
$order_details = $order->getProductsDetail();
$slip_quantity = array();
foreach ($productsRet as $slip_detail) {
$slip_quantity[$slip_detail['id_order_detail']] = $slip_detail;
}
$products = array();
foreach ($order_details as $key => $product) {
if (isset($slip_quantity[$product['id_order_detail']]) && $slip_quantity[$product['id_order_detail']]['product_quantity']) {
$products[$key] = $product;
$products[$key] = array_merge($products[$key], $slip_quantity[$product['id_order_detail']]);
}
}
return $order->getProducts($products);
}
/**
* Get resume of all refund for one product line.
*
* @param $id_order_detail
*/
public static function getProductSlipResume($id_order_detail)
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('
SELECT SUM(product_quantity) product_quantity, SUM(amount_tax_excl) amount_tax_excl, SUM(amount_tax_incl) amount_tax_incl
FROM `' . _DB_PREFIX_ . 'order_slip_detail`
WHERE `id_order_detail` = ' . (int) $id_order_detail);
}
/**
* Get refund details for one product line.
*
* @param $id_order_detail
*/
public static function getProductSlipDetail($id_order_detail)
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT product_quantity, amount_tax_excl, amount_tax_incl, date_add
FROM `' . _DB_PREFIX_ . 'order_slip_detail` osd
LEFT JOIN `' . _DB_PREFIX_ . 'order_slip` os
ON os.id_order_slip = osd.id_order_slip
WHERE osd.`id_order_detail` = ' . (int) $id_order_detail);
}
public function getProducts()
{
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT *, osd.product_quantity
FROM `' . _DB_PREFIX_ . 'order_slip_detail` osd
INNER JOIN `' . _DB_PREFIX_ . 'order_detail` od ON osd.id_order_detail = od.id_order_detail
WHERE osd.`id_order_slip` = ' . (int) $this->id);
$order = new Order($this->id_order);
$products = array();
foreach ($result as $row) {
$order->setProductPrices($row);
$products[] = $row;
}
return $products;
}
public static function getSlipsIdByDate($dateFrom, $dateTo)
{
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT `id_order_slip`
FROM `' . _DB_PREFIX_ . 'order_slip` os
LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON (o.`id_order` = os.`id_order`)
WHERE os.`date_add` BETWEEN \'' . pSQL($dateFrom) . ' 00:00:00\' AND \'' . pSQL($dateTo) . ' 23:59:59\'
' . Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o') . '
ORDER BY os.`date_add` ASC');
$slips = array();
foreach ($result as $slip) {
$slips[] = (int) $slip['id_order_slip'];
}
return $slips;
}
/**
* @deprecated since 1.6.0.10 use OrderSlip::create() instead
*/
public static function createOrderSlip($order, $productList, $qtyList, $shipping_cost = false)
{
Tools::displayAsDeprecated('Use OrderSlip::create() instead');
$product_list = array();
foreach ($productList as $id_order_detail) {
$order_detail = new OrderDetail((int) $id_order_detail);
$product_list[$id_order_detail] = array(
'id_order_detail' => $id_order_detail,
'quantity' => $qtyList[$id_order_detail],
'unit_price' => $order_detail->unit_price_tax_excl,
'amount' => $order_detail->unit_price_tax_incl * $qtyList[$id_order_detail],
);
$shipping = $shipping_cost ? null : false;
}
return OrderSlip::create($order, $product_list, $shipping);
}
public static function create(Order $order, $product_list, $shipping_cost = false, $amount = 0, $amount_choosen = false, $add_tax = true)
{
$currency = new Currency((int) $order->id_currency);
$order_slip = new OrderSlip();
$order_slip->id_customer = (int) $order->id_customer;
$order_slip->id_order = (int) $order->id;
$order_slip->conversion_rate = $currency->conversion_rate;
if ($add_tax) {
$add_or_remove = 'add';
$inc_or_ex_1 = 'excl';
$inc_or_ex_2 = 'incl';
} else {
$add_or_remove = 'remove';
$inc_or_ex_1 = 'incl';
$inc_or_ex_2 = 'excl';
}
$order_slip->{'total_shipping_tax_' . $inc_or_ex_1} = 0;
$order_slip->{'total_shipping_tax_' . $inc_or_ex_2} = 0;
$order_slip->partial = 0;
if ($shipping_cost !== false) {
$order_slip->shipping_cost = true;
$carrier = new Carrier((int) $order->id_carrier);
$address = Address::initialize($order->id_address_delivery, false);
$tax_calculator = $carrier->getTaxCalculator($address);
$order_slip->{'total_shipping_tax_' . $inc_or_ex_1} = ($shipping_cost === null ? $order->{'total_shipping_tax_' . $inc_or_ex_1} : (float) $shipping_cost);
if ($tax_calculator instanceof TaxCalculator) {
$order_slip->{'total_shipping_tax_' . $inc_or_ex_2} = Tools::ps_round($tax_calculator->{$add_or_remove . 'Taxes'}($order_slip->{'total_shipping_tax_' . $inc_or_ex_1}), _PS_PRICE_COMPUTE_PRECISION_);
} else {
$order_slip->{'total_shipping_tax_' . $inc_or_ex_2} = $order_slip->{'total_shipping_tax_' . $inc_or_ex_1};
}
} else {
$order_slip->shipping_cost = false;
}
$order_slip->amount = 0;
$order_slip->{'total_products_tax_' . $inc_or_ex_1} = 0;
$order_slip->{'total_products_tax_' . $inc_or_ex_2} = 0;
foreach ($product_list as &$product) {
$order_detail = new OrderDetail((int) $product['id_order_detail']);
$price = (float) $product['unit_price'];
$quantity = (int) $product['quantity'];
$order_slip_resume = OrderSlip::getProductSlipResume((int) $order_detail->id);
if ($quantity + $order_slip_resume['product_quantity'] > $order_detail->product_quantity) {
$quantity = $order_detail->product_quantity - $order_slip_resume['product_quantity'];
}
if ($quantity == 0) {
continue;
}
if (!Tools::isSubmit('cancelProduct') && $order->hasBeenPaid()) {
$order_detail->product_quantity_refunded += $quantity;
}
$order_detail->save();
$address = Address::initialize($order->id_address_invoice, false);
$id_address = (int) $address->id;
$id_tax_rules_group = Product::getIdTaxRulesGroupByIdProduct((int) $order_detail->product_id);
$tax_calculator = TaxManagerFactory::getManager($address, $id_tax_rules_group)->getTaxCalculator();
$order_slip->{'total_products_tax_' . $inc_or_ex_1} += $price * $quantity;
if (in_array(Configuration::get('PS_ROUND_TYPE'), array(Order::ROUND_ITEM, Order::ROUND_LINE))) {
if (!isset($total_products[$id_tax_rules_group])) {
$total_products[$id_tax_rules_group] = 0;
}
} else {
if (!isset($total_products[$id_tax_rules_group . '_' . $id_address])) {
$total_products[$id_tax_rules_group . '_' . $id_address] = 0;
}
}
$product_tax_incl_line = Tools::ps_round($tax_calculator->{$add_or_remove . 'Taxes'}($price) * $quantity, _PS_PRICE_COMPUTE_PRECISION_);
switch (Configuration::get('PS_ROUND_TYPE')) {
case Order::ROUND_ITEM:
$product_tax_incl = Tools::ps_round($tax_calculator->{$add_or_remove . 'Taxes'}($price), _PS_PRICE_COMPUTE_PRECISION_) * $quantity;
$total_products[$id_tax_rules_group] += $product_tax_incl;
break;
case Order::ROUND_LINE:
$product_tax_incl = $product_tax_incl_line;
$total_products[$id_tax_rules_group] += $product_tax_incl;
break;
case Order::ROUND_TOTAL:
$product_tax_incl = $product_tax_incl_line;
$total_products[$id_tax_rules_group . '_' . $id_address] += $price * $quantity;
break;
}
$product['unit_price_tax_' . $inc_or_ex_1] = $price;
$product['unit_price_tax_' . $inc_or_ex_2] = Tools::ps_round($tax_calculator->{$add_or_remove . 'Taxes'}($price), _PS_PRICE_COMPUTE_PRECISION_);
$product['total_price_tax_' . $inc_or_ex_1] = Tools::ps_round($price * $quantity, _PS_PRICE_COMPUTE_PRECISION_);
$product['total_price_tax_' . $inc_or_ex_2] = Tools::ps_round($product_tax_incl, _PS_PRICE_COMPUTE_PRECISION_);
}
unset($product);
foreach ($total_products as $key => $price) {
if (Configuration::get('PS_ROUND_TYPE') == Order::ROUND_TOTAL) {
$tmp = explode('_', $key);
$address = Address::initialize((int) $tmp[1], true);
$tax_calculator = TaxManagerFactory::getManager($address, $tmp[0])->getTaxCalculator();
$order_slip->{'total_products_tax_' . $inc_or_ex_2} += Tools::ps_round($tax_calculator->{$add_or_remove . 'Taxes'}($price), _PS_PRICE_COMPUTE_PRECISION_);
} else {
$order_slip->{'total_products_tax_' . $inc_or_ex_2} += $price;
}
}
$order_slip->{'total_products_tax_' . $inc_or_ex_2} -= (float) $amount && !$amount_choosen ? (float) $amount : 0;
$order_slip->amount = $amount_choosen ? (float) $amount : $order_slip->{'total_products_tax_' . $inc_or_ex_1};
$order_slip->shipping_cost_amount = $order_slip->total_shipping_tax_incl;
if ((float) $amount && !$amount_choosen) {
$order_slip->order_slip_type = 1;
}
if (((float) $amount && $amount_choosen) || $order_slip->shipping_cost_amount > 0) {
$order_slip->order_slip_type = 2;
}
if (!$order_slip->add()) {
return false;
}
$res = true;
foreach ($product_list as $product) {
$res &= $order_slip->addProductOrderSlip($product);
}
return $res;
}
protected function addProductOrderSlip($product)
{
return Db::getInstance()->insert('order_slip_detail', array(
'id_order_slip' => (int) $this->id,
'id_order_detail' => (int) $product['id_order_detail'],
'product_quantity' => $product['quantity'],
'unit_price_tax_excl' => $product['unit_price_tax_excl'],
'unit_price_tax_incl' => $product['unit_price_tax_incl'],
'total_price_tax_excl' => $product['total_price_tax_excl'],
'total_price_tax_incl' => $product['total_price_tax_incl'],
'amount_tax_excl' => $product['total_price_tax_excl'],
'amount_tax_incl' => $product['total_price_tax_incl'],
));
}
public static function createPartialOrderSlip($order, $amount, $shipping_cost_amount, $order_detail_list)
{
$currency = new Currency($order->id_currency);
$orderSlip = new OrderSlip();
$orderSlip->id_customer = (int) $order->id_customer;
$orderSlip->id_order = (int) $order->id;
$orderSlip->amount = (float) $amount;
$orderSlip->shipping_cost = false;
$orderSlip->shipping_cost_amount = (float) $shipping_cost_amount;
$orderSlip->conversion_rate = $currency->conversion_rate;
$orderSlip->partial = 1;
if (!$orderSlip->add()) {
return false;
}
$orderSlip->addPartialSlipDetail($order_detail_list);
return true;
}
public function addPartialSlipDetail($order_detail_list)
{
foreach ($order_detail_list as $id_order_detail => $tab) {
$order_detail = new OrderDetail($id_order_detail);
$order_slip_resume = OrderSlip::getProductSlipResume($id_order_detail);
if ($tab['amount'] + $order_slip_resume['amount_tax_incl'] > $order_detail->total_price_tax_incl) {
$tab['amount'] = $order_detail->total_price_tax_incl - $order_slip_resume['amount_tax_incl'];
}
if ($tab['amount'] == 0) {
continue;
}
if ($tab['quantity'] + $order_slip_resume['product_quantity'] > $order_detail->product_quantity) {
$tab['quantity'] = $order_detail->product_quantity - $order_slip_resume['product_quantity'];
}
$tab['amount_tax_excl'] = $tab['amount_tax_incl'] = $tab['amount'];
$id_tax = (int) Db::getInstance()->getValue(
'SELECT `id_tax`
FROM `' . _DB_PREFIX_ . 'order_detail_tax`
WHERE `id_order_detail` = ' . (int) $id_order_detail
);
if ($id_tax > 0) {
$rate = (float) Db::getInstance()->getValue(
'SELECT `rate`
FROM `' . _DB_PREFIX_ . 'tax`
WHERE `id_tax` = ' . (int) $id_tax
);
if ($rate > 0) {
$rate = 1 + ($rate / 100);
$tab['amount_tax_excl'] = $tab['amount_tax_excl'] / $rate;
}
}
if ($tab['quantity'] > 0 && $tab['quantity'] > $order_detail->product_quantity_refunded) {
$order_detail->product_quantity_refunded = $tab['quantity'];
$order_detail->save();
}
$insert_order_slip = array(
'id_order_slip' => (int) $this->id,
'id_order_detail' => (int) $id_order_detail,
'product_quantity' => (int) $tab['quantity'],
'amount_tax_excl' => (float) $tab['amount_tax_excl'],
'amount_tax_incl' => (float) $tab['amount_tax_incl'],
);
Db::getInstance()->insert('order_slip_detail', $insert_order_slip);
}
}
public function getEcoTaxTaxesBreakdown()
{
$ecotax_detail = array();
foreach ($this->getOrdersSlipDetail((int) $this->id) as $order_slip_details) {
$row = Db::getInstance()->getRow(
'SELECT `ecotax_tax_rate` as `rate`, `ecotax` as `ecotax_tax_excl`, `ecotax` as `ecotax_tax_incl`, `product_quantity`
FROM `' . _DB_PREFIX_ . 'order_detail`
WHERE `id_order_detail` = ' . (int) $order_slip_details['id_order_detail']
);
if (!isset($ecotax_detail[$row['rate']])) {
$ecotax_detail[$row['rate']] = array('ecotax_tax_incl' => 0, 'ecotax_tax_excl' => 0, 'rate' => $row['rate']);
}
$ecotax_detail[$row['rate']]['ecotax_tax_incl'] += Tools::ps_round(($row['ecotax_tax_excl'] * $order_slip_details['product_quantity']) + ($row['ecotax_tax_excl'] * $order_slip_details['product_quantity'] * $row['rate'] / 100), 2);
$ecotax_detail[$row['rate']]['ecotax_tax_excl'] += Tools::ps_round($row['ecotax_tax_excl'] * $order_slip_details['product_quantity'], 2);
}
return $ecotax_detail;
}
public function getWsOrderSlipDetails()
{
$query = 'SELECT id_order_slip as id, id_order_detail, product_quantity, amount_tax_excl, amount_tax_incl
FROM `' . _DB_PREFIX_ . 'order_slip_detail`
WHERE id_order_slip = ' . (int) $this->id;
$result = Db::getInstance()->executeS($query);
return $result;
}
public function setWsOrderSlipDetails($values)
{
if (Db::getInstance()->execute('DELETE from `' . _DB_PREFIX_ . 'order_slip_detail` where id_order_slip = ' . (int) $this->id)) {
$query = 'INSERT INTO `' . _DB_PREFIX_ . 'order_slip_detail`(`id_order_slip`, `id_order_detail`, `product_quantity`, `amount_tax_excl`, `amount_tax_incl`) VALUES ';
foreach ($values as $value) {
$query .= '(' . (int) $this->id . ', ' . (int) $value['id_order_detail'] . ', ' . (int) $value['product_quantity'] . ', ' .
(isset($value['amount_tax_excl']) ? (float) $value['amount_tax_excl'] : 'NULL') . ', ' .
(isset($value['amount_tax_incl']) ? (float) $value['amount_tax_incl'] : 'NULL') .
'),';
}
$query = rtrim($query, ',');
Db::getInstance()->execute($query);
}
return true;
}
}

View File

@@ -0,0 +1,162 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
class OrderStateCore extends ObjectModel
{
/** @var string Name */
public $name;
/** @var string Template name if there is any e-mail to send */
public $template;
/** @var bool Send an e-mail to customer ? */
public $send_email;
public $module_name;
/** @var bool Allow customer to view and download invoice when order is at this state */
public $invoice;
/** @var string Display state in the specified color */
public $color;
public $unremovable;
/** @var bool Log authorization */
public $logable;
/** @var bool Delivery */
public $delivery;
/** @var bool Hidden */
public $hidden;
/** @var bool Shipped */
public $shipped;
/** @var bool Paid */
public $paid;
/** @var bool Attach PDF Invoice */
public $pdf_invoice;
/** @var bool Attach PDF Delivery Slip */
public $pdf_delivery;
/** @var bool True if carrier has been deleted (staying in database as deleted) */
public $deleted = 0;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'order_state',
'primary' => 'id_order_state',
'multilang' => true,
'fields' => array(
'send_email' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'module_name' => array('type' => self::TYPE_STRING, 'validate' => 'isModuleName'),
'invoice' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'color' => array('type' => self::TYPE_STRING, 'validate' => 'isColor'),
'logable' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'shipped' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'unremovable' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'delivery' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'hidden' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'paid' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'pdf_delivery' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'pdf_invoice' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
/* Lang fields */
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 64),
'template' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isTplName', 'size' => 64),
),
);
protected $webserviceParameters = array(
'fields' => array(
'unremovable' => array(),
'delivery' => array(),
'hidden' => array(),
),
);
const FLAG_NO_HIDDEN = 1; /* 00001 */
const FLAG_LOGABLE = 2; /* 00010 */
const FLAG_DELIVERY = 4; /* 00100 */
const FLAG_SHIPPED = 8; /* 01000 */
const FLAG_PAID = 16; /* 10000 */
/**
* Get all available order statuses.
*
* @param int $id_lang Language id for status name
*
* @return array Order statuses
*/
public static function getOrderStates($id_lang)
{
$cache_id = 'OrderState::getOrderStates_' . (int) $id_lang;
if (!Cache::isStored($cache_id)) {
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'order_state` os
LEFT JOIN `' . _DB_PREFIX_ . 'order_state_lang` osl ON (os.`id_order_state` = osl.`id_order_state` AND osl.`id_lang` = ' . (int) $id_lang . ')
WHERE deleted = 0
ORDER BY `name` ASC');
Cache::store($cache_id, $result);
return $result;
}
return Cache::retrieve($cache_id);
}
/**
* Check if we can make a invoice when order is in this state.
*
* @param int $id_order_state State ID
*
* @return bool availability
*/
public static function invoiceAvailable($id_order_state)
{
$result = false;
if (Configuration::get('PS_INVOICE')) {
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('
SELECT `invoice`
FROM `' . _DB_PREFIX_ . 'order_state`
WHERE `id_order_state` = ' . (int) $id_order_state);
}
return (bool) $result;
}
public function isRemovable()
{
return !($this->unremovable);
}
}

34
classes/order/index.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2019 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../../');
exit;