Container(); $this->db = Shopware()->Db(); $this->eventManager = Shopware()->Events(); $this->config = Shopware()->Config(); $this->numberRangeIncrementer = $container->get(NumberRangeIncrementerInterface::class); $this->contextService = $contextService ?: Shopware()->Container()->get(ContextServiceInterface::class); $this->attributeLoader = Shopware()->Container()->get(DataLoader::class); $this->attributePersister = Shopware()->Container()->get(DataPersister::class); $this->modelManager = $container->get(ModelManager::class); } /** * Get a unique order number * * @return string The reserved order number */ public function sGetOrderNumber() { $number = $this->numberRangeIncrementer->increment('invoice'); $number = $this->eventManager->filter( 'Shopware_Modules_Order_GetOrdernumber_FilterOrdernumber', $number, ['subject' => $this] ); return (string) $number; } /** * Check each basket row for instant downloads * * @param array $basketRow * @param int $orderID * @param int $orderDetailsID * * @return array */ public function handleESDOrder($basketRow, $orderID, $orderDetailsID) { $quantity = $basketRow['quantity']; $basketRow['assignedSerials'] = []; // Check if current order number is an esd variant. $esdProduct = $this->getVariantEsd($basketRow['ordernumber']); if (!$esdProduct || !$esdProduct['id']) { return $basketRow; } if (!$esdProduct['serials']) { // No serial number is needed $this->db->insert('s_order_esd', [ 'serialID' => 0, 'esdID' => $esdProduct['id'], 'userID' => $this->sUserData['additional']['user']['id'], 'orderID' => $orderID, 'orderdetailsID' => $orderDetailsID, 'datum' => new Zend_Db_Expr('NOW()'), ]); return $basketRow; } $availableSerials = $this->getAvailableSerialsOfEsd($esdProduct['id']); if ((\count($availableSerials) <= $this->config->get('esdMinSerials')) || \count($availableSerials) <= $quantity) { // Not enough serial numbers anymore, inform merchant $context = [ 'sArticleName' => $basketRow['articlename'], 'sMail' => $this->sUserData['additional']['user']['email'] ?? null, ]; $mail = Shopware()->TemplateMail()->createMail('sNOSERIALS', $context); if ($this->config->get('sESDMAIL')) { $mail->addTo($this->config->get('sESDMAIL')); } else { $mail->addTo($this->config->get('sMAIL')); } $mail->send(); } // Check if enough serials are available, if not, an email has been sent, and we can return if (\count($availableSerials) < $quantity) { return $basketRow; } for ($i = 1; $i <= $quantity; ++$i) { // Assign serial number $serialId = $availableSerials[$i - 1]['id']; // Update basket row $basketRow['assignedSerials'][] = $availableSerials[$i - 1]['serialnumber']; $this->db->insert('s_order_esd', [ 'serialID' => $serialId, 'esdID' => $esdProduct['id'], 'userID' => $this->sUserData['additional']['user']['id'], 'orderID' => $orderID, 'orderdetailsID' => $orderDetailsID, 'datum' => new Zend_Db_Expr('NOW()'), ]); } return $basketRow; } /** * Delete temporary created order * * @return void */ public function sDeleteTemporaryOrder() { $sessionId = $this->getSession()->offsetGet('sessionId'); if (empty($sessionId)) { return; } $deleteWholeOrder = $this->db->fetchAll(' SELECT * FROM s_order WHERE temporaryID = ? LIMIT 2 ', [$this->getSession()->offsetGet('sessionId')]); foreach ($deleteWholeOrder as $orderDelete) { $this->db->executeUpdate(' DELETE FROM s_order WHERE id = ? ', [$orderDelete['id']]); $this->db->executeUpdate(' DELETE FROM s_order_details WHERE orderID=? ', [$orderDelete['id']]); } } /** * Create temporary order (for order cancellation reports) * * @throws Enlight_Exception * * @return void */ public function sCreateTemporaryOrder() { $this->sShippingData[CartKey::AMOUNT_NUMERIC] = $this->sShippingData[CartKey::AMOUNT_NUMERIC] ?? '0'; if (!$this->sShippingcostsNumeric) { $this->sShippingcostsNumeric = 0.; } if (!$this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC]) { $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC] = $this->sBasketData[CartKey::AMOUNT_NUMERIC]; } $net = '0'; if ($this->isTaxFree( $this->sSYSTEM->sUSERGROUPDATA['tax'], $this->sSYSTEM->sUSERGROUPDATA['id'] )) { $net = '1'; } $dispatchId = '0'; $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC] = round($this->sBasketData[CartKey::AMOUNT_NET_NUMERIC], 2); if ($this->dispatchId) { $dispatchId = $this->dispatchId; } $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC] = round($this->sBasketData[CartKey::AMOUNT_NET_NUMERIC], 2); if (empty($this->sBasketData[CheckoutKey::CURRENCY_NAME])) { $this->sBasketData[CheckoutKey::CURRENCY_NAME] = 'EUR'; } if (empty($this->sBasketData[CheckoutKey::CURRENCY_FACTOR])) { $this->sBasketData[CheckoutKey::CURRENCY_FACTOR] = '1'; } $shop = Shopware()->Shop(); $mainShop = $shop->getMain() !== null ? $shop->getMain() : $shop; $taxfree = '0'; if (!empty($this->sNet)) { // Complete net delivery $net = '1'; $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC] = $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC]; $this->sShippingcostsNumeric = $this->sShippingcostsNumericNet; $taxfree = '1'; } if (empty($this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC])) { $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC] = '0'; } if (empty($this->sBasketData[CartKey::AMOUNT_NET_NUMERIC])) { $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC] = '0'; } $data = [ 'ordernumber' => '0', 'userID' => $this->sUserData['additional']['user']['id'], 'invoice_amount' => $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC], 'invoice_amount_net' => $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC], 'invoice_shipping' => $this->sShippingcostsNumeric, 'invoice_shipping_net' => $this->sShippingcostsNumericNet, 'ordertime' => new Zend_Db_Expr('NOW()'), 'status' => -1, 'paymentID' => $this->getPaymentId(), 'customercomment' => $this->sComment, 'net' => $net, 'taxfree' => $taxfree, 'partnerID' => (string) $this->getSession()->offsetGet('sPartner'), 'temporaryID' => $this->getSession()->offsetGet('sessionId'), 'referer' => (string) $this->getSession()->offsetGet('sReferer'), 'language' => $shop->getId(), 'dispatchID' => $dispatchId, 'currency' => $this->sBasketData[CheckoutKey::CURRENCY_NAME], 'currencyFactor' => $this->sBasketData[CheckoutKey::CURRENCY_FACTOR], 'subshopID' => $mainShop->getId(), 'deviceType' => $this->deviceType, ]; try { $affectedRows = $this->db->insert('s_order', $data); $orderID = $this->db->lastInsertId(); } catch (Exception $e) { throw new Enlight_Exception(\sprintf('##sOrder-sTemporaryOrder-#01:%s', $e->getMessage()), 0, $e); } if (!$affectedRows || !$orderID) { throw new Enlight_Exception('##sOrder-sTemporaryOrder-#01: No rows affected or no order id saved', 0); } // Create order attributes $this->attributePersister->persist($this->orderAttributes, 's_order_attributes', $orderID); foreach ($this->sBasketData[CartKey::POSITIONS] as $basketRow) { if (!$basketRow['price']) { $basketRow['price'] = '0,00'; } $basketRow['articlename'] = html_entity_decode($basketRow['articlename']); $basketRow['articlename'] = strip_tags($basketRow['articlename']); $basketRow['articlename'] = $this->sSYSTEM->sMODULES['sArticles']->sOptimizeText($basketRow['articlename']); if (!$basketRow['esdarticle']) { $basketRow['esdarticle'] = '0'; } if (!$basketRow['modus']) { $basketRow['modus'] = '0'; } if (!$basketRow['taxID']) { $basketRow['taxID'] = '0'; } if (empty($basketRow['releasedate'])) { $basketRow['releasedate'] = null; } $data = [ 'orderID' => $orderID, 'ordernumber' => 0, 'articleID' => $basketRow['articleID'], 'articleDetailID' => $basketRow['additional_details']['articleDetailsID'] ?? null, 'articleordernumber' => $basketRow['ordernumber'], 'price' => $basketRow['priceNumeric'], 'quantity' => $basketRow['quantity'], 'name' => $basketRow['articlename'], 'status' => 0, 'releasedate' => $basketRow['releasedate'], 'modus' => $basketRow['modus'], 'esdarticle' => $basketRow['esdarticle'], 'taxID' => $basketRow['taxID'], 'tax_rate' => $basketRow['tax_rate'], ]; try { $this->db->insert('s_order_details', $data); $orderDetailId = $this->db->lastInsertId(); } catch (Exception $e) { throw new Enlight_Exception(\sprintf('##sOrder-sTemporaryOrder-Position-#02:%s', $e->getMessage()), 0, $e); } // Create order detail attributes $attributeData = $this->attributeLoader->load('s_order_basket_attributes', $basketRow['id']); $this->attributePersister->persist($attributeData, 's_order_details_attributes', $orderDetailId); } // For every product in basket } /** * Finally save order and send order confirmation to customer * * @return string|false */ public function sSaveOrder() { $this->sComment = stripslashes($this->sComment ?? ''); $this->sComment = stripcslashes($this->sComment); $this->sShippingData[CartKey::AMOUNT_NUMERIC] = $this->sShippingData[CartKey::AMOUNT_NUMERIC] ?? '0'; if ($this->isTransactionExist($this->bookingId)) { return false; } // Insert basic-data of the order $orderNumber = $this->sGetOrderNumber(); $this->sOrderNumber = $orderNumber; if (!$this->sShippingcostsNumeric) { $this->sShippingcostsNumeric = 0.; } if (!$this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC]) { $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC] = $this->sBasketData[CartKey::AMOUNT_NUMERIC]; } if ($this->isTaxFree($this->sSYSTEM->sUSERGROUPDATA['tax'], $this->sSYSTEM->sUSERGROUPDATA['id'])) { $net = '1'; } else { $net = '0'; } if ($this->dispatchId) { $dispatchId = $this->dispatchId; } else { $dispatchId = '0'; } $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC] = round($this->sBasketData[CartKey::AMOUNT_NET_NUMERIC], 2); if (empty($this->sBasketData[CheckoutKey::CURRENCY_NAME])) { $this->sBasketData[CheckoutKey::CURRENCY_NAME] = 'EUR'; } if (empty($this->sBasketData[CheckoutKey::CURRENCY_FACTOR])) { $this->sBasketData[CheckoutKey::CURRENCY_FACTOR] = '1'; } $shop = Shopware()->Shop(); $mainShop = $shop->getMain() !== null ? $shop->getMain() : $shop; $taxfree = '0'; if (!empty($this->sNet)) { // Complete net delivery $net = '1'; $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC] = $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC]; $this->sShippingcostsNumeric = $this->sShippingcostsNumericNet; $taxfree = '1'; } $partner = $this->getPartnerCode( $this->sUserData['additional']['user']['affiliate'] ); $ip = Shopware()->Container()->get(IpAnonymizerInterface::class) ->anonymize( (string) Shopware()->Container()->get('request_stack')->getCurrentRequest()->getClientIp() ); $orderParams = [ 'ordernumber' => $orderNumber, 'userID' => $this->sUserData['additional']['user']['id'], 'invoice_amount' => $this->sBasketData[CartKey::AMOUNT_WITH_TAX_NUMERIC], 'invoice_amount_net' => $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC], 'invoice_shipping' => (float) $this->sShippingcostsNumeric, 'invoice_shipping_net' => (float) $this->sShippingcostsNumericNet, 'invoice_shipping_tax_rate' => isset($this->sBasketData[CheckoutKey::SHIPPING_COSTS_TAX_PROPORTIONAL]) ? 0 : ($this->sBasketData[CheckoutKey::SHIPPING_COSTS_TAX] ?? 0), 'ordertime' => new Zend_Db_Expr('NOW()'), 'changed' => new Zend_Db_Expr('NOW()'), 'status' => 0, 'cleared' => 17, 'paymentID' => $this->getPaymentId(), 'transactionID' => (string) $this->bookingId, 'customercomment' => $this->sComment, 'net' => $net, 'taxfree' => $taxfree, 'partnerID' => (string) $partner, 'temporaryID' => (string) $this->uniqueID, 'referer' => (string) $this->getSession()->offsetGet('sReferer'), 'language' => $shop->getId(), 'dispatchID' => $dispatchId, 'currency' => $this->sBasketData[CheckoutKey::CURRENCY_NAME], 'currencyFactor' => $this->sBasketData[CheckoutKey::CURRENCY_FACTOR], 'subshopID' => $mainShop->getId(), 'remote_addr' => $ip, 'deviceType' => $this->deviceType, 'is_proportional_calculation' => isset($this->sBasketData[CheckoutKey::SHIPPING_COSTS_TAX_PROPORTIONAL]) ? 1 : 0, ]; $orderParams = $this->eventManager->filter( 'Shopware_Modules_Order_SaveOrder_FilterParams', $orderParams, ['subject' => $this] ); try { $this->db->beginTransaction(); $affectedRows = $this->db->insert('s_order', $orderParams); $orderID = (int) $this->db->lastInsertId(); $this->db->commit(); } catch (Exception $e) { $this->db->rollBack(); throw new Enlight_Exception(\sprintf('Shopware Order Fatal-Error %s :%s', $_SERVER['HTTP_HOST'], $e->getMessage()), 0, $e); } if (!$affectedRows || !$orderID) { throw new Enlight_Exception(\sprintf('Shopware Order Fatal-Error %s : No rows affected or no order id created.', $_SERVER['HTTP_HOST']), 0); } try { $paymentData = Shopware()->Modules()->Admin() ->sGetPaymentMeanById($this->getPaymentId(), Shopware()->Modules()->Admin()->sGetUserData()); $paymentClass = Shopware()->Modules()->Admin()->sInitiatePaymentClass($paymentData); if ($paymentClass instanceof BasePaymentMethod) { $paymentClass->createPaymentInstance( $orderID, $this->sUserData['additional']['user']['id'], $this->getPaymentId() ); } } catch (Exception $e) { // Payment method code failure } $attributeData = $this->eventManager->filter( 'Shopware_Modules_Order_SaveOrder_FilterAttributes', $this->orderAttributes, [ 'subject' => $this, 'orderID' => $orderID, 'orderParams' => $orderParams, ] ); $this->attributePersister->persist($attributeData, 's_order_attributes', $orderID); $attributes = $this->attributeLoader->load('s_order_attributes', $orderID); unset($attributes['id'], $attributes['orderID']); $esdOrder = null; foreach ($this->sBasketData[CartKey::POSITIONS] as $key => $basketRow) { $basketRow = $this->formatBasketRow($basketRow); $preparedQuery = ' INSERT INTO s_order_details (orderID, ordernumber, articleID, articleordernumber, price, quantity, name, status, releasedate, modus, esdarticle, taxID, tax_rate, ean, unit, pack_unit, articleDetailID ) VALUES (%d, %s, %d, %s, %f, %d, %s, %d, %s, %d, %d, %d, %f, %s, %s, %s, %s) '; $sql = \sprintf( $preparedQuery, $orderID, $this->db->quote((string) $orderNumber), $basketRow['articleID'], $this->db->quote((string) $basketRow['ordernumber']), $basketRow['priceNumeric'], $basketRow['quantity'], $this->db->quote((string) $basketRow['articlename']), 0, $this->db->quote((string) $basketRow['releasedate']), $basketRow['modus'], $basketRow['esdarticle'], $basketRow['taxID'], $basketRow['tax_rate'], $this->db->quote((string) $basketRow['ean']), $this->db->quote((string) ($basketRow['itemUnit'] ?? '')), $this->db->quote((string) ($basketRow['packunit'] ?? '')), $basketRow['additional_details']['articleDetailsID'] ?? 'null' ); $sql = $this->eventManager->filter('Shopware_Modules_Order_SaveOrder_FilterDetailsSQL', $sql, [ 'subject' => $this, 'row' => $basketRow, 'user' => $this->sUserData, 'order' => ['id' => $orderID, 'number' => $orderNumber], ]); // Check for individual voucher - code if ($basketRow['modus'] == CartPositionsMode::VOUCHER) { // reserve the basket voucher for the current user. $this->reserveVoucher( $basketRow['ordernumber'], $this->sUserData['additional']['user']['id'], $basketRow['articleID'] ); } if ($basketRow['esdarticle']) { $esdOrder = true; } try { $this->db->executeUpdate($sql); $orderdetailsID = (int) $this->db->lastInsertId(); } catch (Exception $e) { throw new Enlight_Exception(\sprintf('Shopware Order Fatal-Error %s :%s', $_SERVER['HTTP_HOST'], $e->getMessage()), 0, $e); } $this->sBasketData[CartKey::POSITIONS][$key]['orderDetailId'] = $orderdetailsID; // Save attributes $attributeData = $this->attributeLoader->load('s_order_basket_attributes', $basketRow['id']); $attributeData = $this->eventManager->filter( 'Shopware_Modules_Order_SaveOrder_FilterDetailAttributes', $attributeData, [ 'subject' => $this, 'basketRow' => $basketRow, 'orderdetailsID' => $orderdetailsID, ] ); $this->attributePersister->persist($attributeData, 's_order_details_attributes', $orderdetailsID); $detailAttributes = $this->attributeLoader->load('s_order_details_attributes', $orderdetailsID); unset($detailAttributes['id'], $detailAttributes['detailID']); $this->sBasketData[CartKey::POSITIONS][$key]['attributes'] = $detailAttributes; // Update sales and stock if ($basketRow['priceNumeric'] >= 0) { $this->refreshOrderedVariant( $basketRow['ordernumber'], $basketRow['quantity'] ); } // For esd-products, assign serial number if needed // Check if this product is esd-only (check in variants, too -> later) if ($basketRow['esdarticle']) { $basketRow = $this->handleESDOrder($basketRow, $orderID, $orderdetailsID); // Add assignedSerials to basketcontent if (!empty($basketRow['assignedSerials'])) { $this->sBasketData[CartKey::POSITIONS][$key]['serials'] = $basketRow['assignedSerials']; } } } // For every product in basket $this->eventManager->notify('Shopware_Modules_Order_SaveOrder_ProcessDetails', [ 'subject' => $this, 'details' => $this->sBasketData[CartKey::POSITIONS], 'orderId' => $orderID, ]); // Save Billing and Shipping-Address to retrace in future $this->sSaveBillingAddress($this->sUserData['billingaddress'], $orderID); $this->sSaveShippingAddress($this->sUserData['shippingaddress'], $orderID); $this->sUserData = $this->getUserDataForMail($this->sUserData); $details = $this->getOrderDetailsForMail( $this->sBasketData[CartKey::POSITIONS] ); $variables = [ 'sOrderDetails' => $details, 'billingaddress' => $this->sUserData['billingaddress'], 'shippingaddress' => $this->sUserData['shippingaddress'], 'additional' => $this->sUserData['additional'], 'sShippingCosts' => $this->sSYSTEM->sMODULES['sArticles']->sFormatPrice($this->sShippingcosts) . ' ' . $this->sBasketData[CheckoutKey::CURRENCY_NAME], 'sAmount' => $this->sAmountWithTax ? $this->sSYSTEM->sMODULES['sArticles']->sFormatPrice($this->sAmountWithTax) . ' ' . $this->sBasketData[CheckoutKey::CURRENCY_NAME] : $this->sSYSTEM->sMODULES['sArticles']->sFormatPrice($this->sAmount) . ' ' . $this->sBasketData[CheckoutKey::CURRENCY_NAME], 'sAmountNumeric' => $this->sAmountWithTax ? $this->sAmountWithTax : $this->sAmount, 'sAmountNet' => $this->sSYSTEM->sMODULES['sArticles']->sFormatPrice($this->sBasketData[CartKey::AMOUNT_NET_NUMERIC]) . ' ' . $this->sBasketData[CheckoutKey::CURRENCY_NAME], 'sAmountNetNumeric' => $this->sBasketData[CartKey::AMOUNT_NET_NUMERIC], 'sTaxRates' => $this->sBasketData[CheckoutKey::TAX_RATES] ?? null, 'ordernumber' => $orderNumber, 'sOrderDay' => date('d.m.Y'), 'sOrderTime' => date('H:i'), 'sComment' => $this->sComment, 'attributes' => $attributes, 'sEsd' => $esdOrder, ]; if ($dispatchId) { $variables['sDispatch'] = $this->sSYSTEM->sMODULES['sAdmin']->sGetPremiumDispatch($dispatchId); } if ($this->bookingId) { $variables['sBookingID'] = $this->bookingId; } // Completed - Garbage basket / temporary - order $this->sDeleteTemporaryOrder(); $this->db->executeUpdate( 'DELETE FROM s_order_basket WHERE sessionID=?', [$this->getSession()->offsetGet('sessionId')] ); $confirmMailDeliveryFailed = false; try { $this->sendMail($variables); } catch (Exception $e) { $confirmMailDeliveryFailed = true; $email = $this->sUserData['additional']['user']['email']; $this->logOrderMailException($e, $orderNumber, $email); } // Check if voucher is affected $this->sTellFriend(); if ($this->getSession()->offsetExists('sOrderVariables')) { $variables = $this->getSession()->offsetGet('sOrderVariables'); $variables['sOrderNumber'] = $orderNumber; $variables['confirmMailDeliveryFailed'] = $confirmMailDeliveryFailed; $this->getSession()->offsetSet('sOrderVariables', $variables); } $this->eventManager->notify('Shopware_Modules_Order_SaveOrder_OrderCreated', [ 'subject' => $this, 'details' => $this->sBasketData[CartKey::POSITIONS], 'orderId' => $orderID, 'orderNumber' => $orderNumber, ]); return $orderNumber; } /** * send order confirmation mail * * @param array $variables */ public function sendMail($variables) { $variables = $this->eventManager->filter( 'Shopware_Modules_Order_SendMail_FilterVariables', $variables, ['subject' => $this] ); $shopContext = $this->contextService->getShopContext(); $context = [ 'sOrderDetails' => $variables['sOrderDetails'] ?? null, 'billingaddress' => $variables['billingaddress'] ?? null, 'shippingaddress' => $variables['shippingaddress'] ?? null, 'additional' => $variables['additional'], 'sTaxRates' => $variables[CheckoutKey::TAX_RATES] ?? null, 'sShippingCosts' => $variables['sShippingCosts'] ?? null, 'sAmount' => $variables[CheckoutKey::AMOUNT] ?? null, 'sAmountNumeric' => $variables['sAmountNumeric'] ?? null, 'sAmountNet' => $variables['sAmountNet'] ?? null, 'sAmountNetNumeric' => $variables['sAmountNetNumeric'] ?? null, 'sOrderNumber' => $variables['ordernumber'] ?? null, 'sOrderDay' => $variables['sOrderDay'] ?? null, 'sOrderTime' => $variables['sOrderTime'] ?? null, 'sComment' => $variables['sComment'] ?? null, 'attributes' => $variables['attributes'] ?? null, 'sCurrency' => $this->sBasketData[CheckoutKey::CURRENCY_NAME] ?? null, 'sLanguage' => $shopContext->getShop()->getId(), 'sSubShop' => $shopContext->getShop()->getId(), 'sEsd' => $variables['sEsd'] ?? null, 'sNet' => $this->sNet, ]; // Support for individual payment means with custom-tables if (!empty($variables['additional']['payment']['table'])) { $paymentTable = $this->db->fetchRow( "SELECT * FROM {$variables['additional']['payment']['table']} WHERE userID=?", [$variables['additional']['user']['id']] ); $context['sPaymentTable'] = $paymentTable ?: []; } else { $context['sPaymentTable'] = []; } if (isset($variables['sDispatch'])) { $context['sDispatch'] = $variables['sDispatch']; } if (isset($variables['sBookingID'])) { $context['sBookingID'] = $variables['sBookingID']; } $context = $this->eventManager->filter( 'Shopware_Modules_Order_SendMail_FilterContext', $context, ['subject' => $this] ); $mail = null; if ($event = $this->eventManager->notifyUntil( 'Shopware_Modules_Order_SendMail_Create', [ 'subject' => $this, 'context' => $context, 'variables' => $variables, ] )) { $mail = $event->getReturn(); } if (!($mail instanceof Zend_Mail)) { $overrideConfig = $this->eventManager->filter( 'Shopware_Modules_Order_SendMail_CreateMail_FilterOverrideConfig', [], [ 'subject' => $this, 'context' => $context, 'variables' => $variables, ] ); $mail = Shopware()->TemplateMail()->createMail('sORDER', $context, null, $overrideConfig); } $mail->addTo($this->sUserData['additional']['user']['email'] ?? ''); if (!$this->config->get('sNO_ORDER_MAIL')) { $mail->addBcc($this->config->get('sMAIL')); } $mail = $this->eventManager->filter('Shopware_Modules_Order_SendMail_Filter', $mail, [ 'subject' => $this, 'context' => $context, 'variables' => $variables, ]); if (!($mail instanceof Zend_Mail)) { return; } $this->eventManager->notify( 'Shopware_Modules_Order_SendMail_BeforeSend', [ 'subject' => $this, 'mail' => $mail, 'context' => $context, 'variables' => $variables, ] ); $shouldSendMail = !(bool) $this->eventManager->notifyUntil( 'Shopware_Modules_Order_SendMail_Send', [ 'subject' => $this, 'mail' => $mail, 'context' => $context, 'variables' => $variables, ] ); if ($shouldSendMail && $this->config->get('sendOrderMail')) { $mail->send(); } } /** * Save order billing address * * @param array $address * @param int $id * * @throws Exception * * @return int */ public function sSaveBillingAddress($address, $id) { /** @var Customer $customer */ $customer = $this->modelManager->find(Customer::class, $address['userID']); $sql = ' INSERT INTO s_order_billingaddress ( userID, orderID, customernumber, company, department, salutation, firstname, lastname, street, zipcode, city, phone, countryID, stateID, ustid, additional_address_line1, additional_address_line2, title ) VALUES ( :userID, :orderID, :customernumber, :company, :department, :salutation, :firstname, :lastname, :street, :zipcode, :city, :phone, :countryID, :stateID, :ustid, :additional_address_line1, :additional_address_line2, :title ) '; $sql = $this->eventManager->filter( 'Shopware_Modules_Order_SaveBilling_FilterSQL', $sql, ['subject' => $this, 'address' => $address, 'id' => $id] ); $array = [ ':userID' => $address['userID'], ':orderID' => $id, ':customernumber' => $customer->getNumber(), ':company' => (string) $address['company'], ':department' => (string) $address['department'], ':salutation' => (string) $address['salutation'], ':firstname' => (string) $address['firstname'], ':lastname' => (string) $address['lastname'], ':street' => (string) $address['street'], ':zipcode' => (string) $address['zipcode'], ':city' => (string) $address['city'], ':phone' => (string) $address['phone'], ':countryID' => $address['countryID'], ':stateID' => $address['stateID'], ':ustid' => $address['ustid'], ':additional_address_line1' => $address['additional_address_line1'] ?? null, ':additional_address_line2' => $address['additional_address_line2'] ?? null, ':title' => $address['title'] ?? null, ]; $array = $this->eventManager->filter( 'Shopware_Modules_Order_SaveBilling_FilterArray', $array, ['subject' => $this, 'address' => $address, 'id' => $id] ); $result = $this->db->executeUpdate($sql, $array); $billingID = $this->db->lastInsertId(); $billingAddressId = null; if ($this->session !== null) { $billingAddressId = $this->session->get('checkoutBillingAddressId'); } if ($billingAddressId === null) { $defaultBillingAddress = $customer->getDefaultBillingAddress(); if (!$defaultBillingAddress instanceof Address) { throw new RuntimeException('Customer does not have a default billing address'); } $billingAddressId = $defaultBillingAddress->getId(); } $attributes = $this->attributeLoader->load('s_user_addresses_attributes', $billingAddressId); if (!\is_array($attributes)) { $attributes = []; } $this->attributePersister->persist($attributes, 's_order_billingaddress_attributes', $billingID); return $result; } /** * Save order shipping address * * @param array $address * @param int $id * * @throws Exception * * @return int */ public function sSaveShippingAddress($address, $id) { $sql = ' INSERT INTO s_order_shippingaddress ( userID, orderID, company, department, salutation, firstname, lastname, street, zipcode, city, phone, countryID, stateID, additional_address_line1, additional_address_line2, title ) VALUES ( :userID, :orderID, :company, :department, :salutation, :firstname, :lastname, :street, :zipcode, :city, :phone, :countryID, :stateID, :additional_address_line1, :additional_address_line2, :title ) '; $sql = $this->eventManager->filter( 'Shopware_Modules_Order_SaveShipping_FilterSQL', $sql, ['subject' => $this, 'address' => $address, 'id' => $id] ); $array = [ ':userID' => $address['userID'], ':orderID' => $id, ':company' => (string) $address['company'], ':department' => (string) $address['department'], ':salutation' => (string) $address['salutation'], ':firstname' => (string) $address['firstname'], ':lastname' => (string) $address['lastname'], ':street' => (string) $address['street'], ':zipcode' => (string) $address['zipcode'], ':city' => (string) $address['city'], ':phone' => (string) ($address['phone'] ?? ''), ':countryID' => $address['countryID'], ':stateID' => $address['stateID'], ':additional_address_line1' => (string) ($address['additional_address_line1'] ?? ''), ':additional_address_line2' => (string) ($address['additional_address_line2'] ?? ''), ':title' => (string) ($address['title'] ?? ''), ]; $array = $this->eventManager->filter( 'Shopware_Modules_Order_SaveShipping_FilterArray', $array, ['subject' => $this, 'address' => $address, 'id' => $id] ); $result = $this->db->executeUpdate($sql, $array); $shippingId = $this->db->lastInsertId(); $shippingAddressId = null; if ($this->session !== null) { $shippingAddressId = $this->session->get('checkoutShippingAddressId'); } if ($shippingAddressId === null) { /** @var Customer $customer */ $customer = $this->modelManager->getRepository(Customer::class)->find($address['userID']); $defaultShippingAddress = $customer->getDefaultShippingAddress(); if (!$defaultShippingAddress instanceof Address) { throw new RuntimeException('Customer does not have a default billing address'); } $shippingAddressId = $defaultShippingAddress->getId(); } $attributes = $this->attributeLoader->load('s_user_addresses_attributes', $shippingAddressId); $this->attributePersister->persist($attributes, 's_order_shippingaddress_attributes', $shippingId); return $result; } /** * Check if this order could be referred to a previous recommendation */ public function sTellFriend() { $checkMail = $this->sUserData['additional']['user']['email']; $tmpSQL = ' SELECT * FROM s_emarketing_tellafriend WHERE confirmed=0 AND recipient=? '; $checkIfUserFound = $this->db->fetchRow($tmpSQL, [$checkMail]); if ($checkIfUserFound) { $this->db->executeUpdate(' UPDATE s_emarketing_tellafriend SET confirmed=1 WHERE recipient=? ', [$checkMail]); $advertiser = $this->db->fetchRow(' SELECT email, firstname, lastname FROM s_user WHERE s_user.id=? ', [$checkIfUserFound['sender']]); if (!$advertiser) { return; } $context = [ 'customer' => $advertiser['firstname'] . ' ' . $advertiser['lastname'], 'user' => $this->sUserData['billingaddress']['firstname'] . ' ' . $this->sUserData['billingaddress']['lastname'], 'voucherValue' => $this->config->get('sVOUCHERTELLFRIENDVALUE'), 'voucherCode' => $this->config->get('sVOUCHERTELLFRIENDCODE'), ]; $mail = Shopware()->TemplateMail()->createMail('sVOUCHER', $context); $mail->addTo($advertiser['email']); $mail->send(); } // - if user found } // Tell-a-friend /** * Send status mail * * @return Enlight_Components_Mail */ public function sendStatusMail(Enlight_Components_Mail $mail) { $this->eventManager->notify('Shopware_Controllers_Backend_OrderState_Send_BeforeSend', [ 'subject' => Shopware()->Front(), 'mail' => $mail, ]); if (!empty($this->config->OrderStateMailAck)) { $mail->addBcc($this->config->OrderStateMailAck); } /** @var Enlight_Components_Mail $return */ $return = $mail->send(); return $return; } /** * Create status mail * * @param int $orderId * @param int $statusId * @param string|null $templateName * * @return Enlight_Components_Mail|null */ public function createStatusMail($orderId, $statusId, $templateName = null) { $statusId = (int) $statusId; $orderId = (int) $orderId; if (empty($templateName)) { $templateName = 'sORDERSTATEMAIL' . $statusId; } if ($orderId === 0) { return null; } $mailModel = $this->modelManager->getRepository(Mail::class)->findOneBy( ['name' => $templateName] ); if (!$mailModel instanceof Mail) { return null; } $order = $this->getOrderForStatusMail($orderId); $orderDetails = $this->getOrderDetailsForStatusMail($orderId); $dispatch = null; if (!empty($order['dispatchID'])) { $dispatch = $this->db->fetchRow(' SELECT id, name, description FROM s_premium_dispatch WHERE id=? ', [$order['dispatchID']]); } $user = $this->getCustomerInformationByOrderId($orderId); if (empty($order) || empty($orderDetails) || empty($user)) { return null; } $repository = $this->modelManager->getRepository(Shop::class); $shopId = is_numeric($order['language']) ? $order['language'] : $order['subshopID']; // The (sub-)shop might be inactive by now, so that's why we use `getById` instead of `getActiveById` $shop = $repository->getById($shopId); if ($shop === null) { throw new ModelNotFoundException(Shop::class, $shopId); } Shopware()->Container()->get(ShopRegistrationServiceInterface::class)->registerShop($shop); $dispatch = Shopware()->Modules()->Admin()->sGetDispatchTranslation($dispatch); $payment = Shopware()->Modules()->Admin()->sGetPaymentTranslation(['id' => $order['paymentID']]); $order['status_description'] = Shopware()->Snippets()->getNamespace('backend/static/order_status')->get( $order['status_name'], $order['status_description'] ); $order['cleared_description'] = Shopware()->Snippets()->getNamespace('backend/static/payment_status')->get( $order['cleared_name'], $order['cleared_description'] ); if (!empty($payment['description'])) { $order['payment_description'] = $payment['description']; } $context = [ 'sOrder' => $order, 'sOrderDetails' => $orderDetails, 'sUser' => $user, ]; if (!empty($dispatch)) { $context['sDispatch'] = $dispatch; } $result = $this->eventManager->notify('Shopware_Controllers_Backend_OrderState_Notify', [ 'subject' => Shopware()->Front(), 'id' => $orderId, 'status' => $statusId, 'mailname' => $templateName, ]); if (!empty($result)) { $context['EventResult'] = $result->getValues(); } $mail = Shopware()->TemplateMail()->createMail($templateName, $context, $shop); $return = [ 'content' => $mail->getPlainBodyText() ?? '', 'subject' => $mail->getPlainSubject() ?? '', 'email' => trim($user['email']), 'frommail' => $mail->getFrom(), 'fromname' => $mail->getFromName(), ]; $return = $this->eventManager->filter('Shopware_Controllers_Backend_OrderState_Filter', $return, [ 'subject' => Shopware()->Front(), 'id' => $orderId, 'status' => $statusId, 'mailname' => $templateName, 'mail' => $mail, 'engine' => Shopware()->Template(), ]); $mail->clearSubject(); $mail->setSubject($return['subject']); $mail->setBodyText($return[CartKey::POSITIONS]); $mail->clearFrom(); $mail->setFrom($return['frommail'], $return['fromname']); $mail->addTo($return['email']); return $mail; } /** * Set payment status by order id * * @param int $orderId * @param int $paymentStatusId * @param bool $sendStatusMail * @param string|null $comment */ public function setPaymentStatus($orderId, $paymentStatusId, $sendStatusMail = false, $comment = null) { $previousStatusId = $this->getOrderPaymentStatus($orderId); if ($paymentStatusId == $previousStatusId) { return; } $this->db->executeUpdate( 'UPDATE s_order SET cleared = :paymentStatus WHERE id = :orderId;', [ 'paymentStatus' => $paymentStatusId, 'orderId' => $orderId, ] ); $sql = ' INSERT INTO s_order_history ( orderID, userID, previous_order_status_id, order_status_id, previous_payment_status_id, payment_status_id, comment, change_date ) SELECT id, NULL, status, status, :previousStatus, :currentStatus, :comment, NOW() FROM s_order WHERE id = :orderId '; $this->db->executeUpdate($sql, [ ':previousStatus' => $previousStatusId, ':currentStatus' => $paymentStatusId, ':comment' => $comment, ':orderId' => $orderId, ]); if ($sendStatusMail) { $mail = $this->createStatusMail($orderId, $paymentStatusId); if ($mail) { $this->sendStatusMail($mail); } } } /** * Set order status by order id * * @param int $orderId * @param int $orderStatusId * @param bool $sendStatusMail * @param string|null $comment */ public function setOrderStatus($orderId, $orderStatusId, $sendStatusMail = false, $comment = null) { $previousStatusId = $this->getOrderStatus($orderId); if ($orderStatusId == $previousStatusId) { return; } $this->db->executeUpdate( 'UPDATE s_order SET status = :status WHERE id = :orderId;', [':status' => $orderStatusId, ':orderId' => $orderId] ); $sql = ' INSERT INTO s_order_history ( orderID, userID, previous_order_status_id, order_status_id, previous_payment_status_id, payment_status_id, comment, change_date ) SELECT id, NULL, :previousStatus, :currentStatus, cleared, cleared, :comment, NOW() FROM s_order WHERE id = :orderId '; $this->db->executeUpdate($sql, [ ':previousStatus' => $previousStatusId, ':currentStatus' => $orderStatusId, ':comment' => $comment, ':orderId' => $orderId, ]); if ($sendStatusMail) { $mail = $this->createStatusMail($orderId, $orderStatusId); if ($mail) { $this->sendStatusMail($mail); } } } /** * Setter for config * * @param Shopware_Components_Config $config */ public function setConfig($config) { $this->config = $config; } /** * Getter for config * * @return Shopware_Components_Config */ public function getConfig() { return $this->config; } /** * Replacement for: Shopware()->Api()->Export()->sGetOrders(array('orderID' => $orderId)); * * @param int $orderId * * @return array|false */ public function getOrderById($orderId) { $sql = <<<'EOT' SELECT `o`.`id` AS `orderID`, `o`.`ordernumber`, `o`.`ordernumber` AS `order_number`, `o`.`userID`, `o`.`userID` AS `customerID`, `o`.`invoice_amount`, `o`.`invoice_amount_net`, `o`.`invoice_shipping`, `o`.`invoice_shipping_net`, `o`.`ordertime` AS `ordertime`, `o`.`status`, `o`.`status` AS `statusID`, `o`.`cleared` AS `cleared`, `o`.`cleared` AS `clearedID`, `o`.`paymentID` AS `paymentID`, `o`.`transactionID` AS `transactionID`, `o`.`comment`, `o`.`customercomment`, `o`.`net`, `o`.`net` AS `netto`, `o`.`partnerID`, `o`.`temporaryID`, `o`.`referer`, o.cleareddate, o.cleareddate AS cleared_date, o.trackingcode, o.language, o.currency, o.currencyFactor, o.subshopID, o.dispatchID, cu.id AS currencyID, `c`.`name` AS `cleared_name`, `c`.`description` AS `cleared_description`, `s`.`name` AS `status_name`, `s`.`description` AS `status_description`, `p`.`description` AS `payment_description`, `d`.`name` AS `dispatch_description`, `cu`.`name` AS `currency_description` FROM `s_order` AS `o` LEFT JOIN `s_core_states` AS `s` ON (`o`.`status` = `s`.`id`) LEFT JOIN `s_core_states` AS `c` ON (`o`.`cleared` = `c`.`id`) LEFT JOIN `s_core_paymentmeans` AS `p` ON (`o`.`paymentID` = `p`.`id`) LEFT JOIN `s_premium_dispatch` AS `d` ON (`o`.`dispatchID` = `d`.`id`) LEFT JOIN `s_core_currencies` AS `cu` ON (`o`.`currency` = `cu`.`currency`) WHERE `o`.`id` = :orderId EOT; return $this->db->fetchRow($sql, ['orderId' => $orderId]); } /** * Replacement for: Shopware()->Api()->Export()->sOrderDetails(array('orderID' => $orderId)); * * Returns order details for a given orderId * * @param int $orderId * * @return array */ public function getOrderDetailsByOrderId($orderId) { $sql = <<<'EOT' SELECT `d`.`id` AS `orderdetailsID`, `d`.`orderID` AS `orderID`, `d`.`ordernumber`, `d`.`articleID`, `d`.`articleordernumber`, `d`.`price` AS `price`, `d`.`quantity` AS `quantity`, `d`.`price`*`d`.`quantity` AS `invoice`, `d`.`name`, `d`.`status`, `d`.`shipped`, `d`.`shippedgroup`, `d`.`releasedate`, `d`.`modus`, `d`.`esdarticle`, `d`.`taxID`, `t`.`tax`, `d`.`tax_rate`, `d`.`esdarticle` AS `esd` FROM `s_order_details` AS `d` LEFT JOIN `s_core_tax` AS `t` ON `t`.`id` = `d`.`taxID` WHERE `d`.`orderID` = :orderId ORDER BY `orderdetailsID` ASC EOT; return $this->db->fetchAll($sql, ['orderId' => $orderId]); } /** * Replacement for: Shopware()->Api()->Export()->sOrderCustomers(array('orderID' => $orderId)); * * @param int $orderId * * @return array|false */ public function getCustomerInformationByOrderId($orderId) { $sql = <<<'EOT' SELECT `b`.`company` AS `billing_company`, `b`.`department` AS `billing_department`, `b`.`salutation` AS `billing_salutation`, `u`.`customernumber`, `b`.`firstname` AS `billing_firstname`, `b`.`lastname` AS `billing_lastname`, `b`.`street` AS `billing_street`, `b`.`additional_address_line1` AS `billing_additional_address_line1`, `b`.`additional_address_line2` AS `billing_additional_address_line2`, `b`.`zipcode` AS `billing_zipcode`, `b`.`city` AS `billing_city`, `b`.`phone` AS `phone`, `b`.`phone` AS `billing_phone`, `b`.`countryID` AS `billing_countryID`, `b`.`stateID` AS `billing_stateID`, `bc`.`countryname` AS `billing_country`, `bc`.`countryiso` AS `billing_countryiso`, `bca`.`name` AS `billing_countryarea`, `bc`.`countryen` AS `billing_countryen`, `b`.`ustid`, `ba`.`text1` AS `billing_text1`, `ba`.`text2` AS `billing_text2`, `ba`.`text3` AS `billing_text3`, `ba`.`text4` AS `billing_text4`, `ba`.`text5` AS `billing_text5`, `ba`.`text6` AS `billing_text6`, `b`.`orderID` AS `orderID`, `s`.`company` AS `shipping_company`, `s`.`department` AS `shipping_department`, `s`.`salutation` AS `shipping_salutation`, `s`.`firstname` AS `shipping_firstname`, `s`.`lastname` AS `shipping_lastname`, `s`.`street` AS `shipping_street`, `s`.`additional_address_line1` AS `shipping_additional_address_line1`, `s`.`additional_address_line2` AS `shipping_additional_address_line2`, `s`.`zipcode` AS `shipping_zipcode`, `s`.`city` AS `shipping_city`, `s`.`stateID` AS `shipping_stateID`, `s`.`countryID` AS `shipping_countryID`, `sc`.`countryname` AS `shipping_country`, `sc`.`countryiso` AS `shipping_countryiso`, `sca`.`name` AS `shipping_countryarea`, `sc`.`countryen` AS `shipping_countryen`, `sa`.`text1` AS `shipping_text1`, `sa`.`text2` AS `shipping_text2`, `sa`.`text3` AS `shipping_text3`, `sa`.`text4` AS `shipping_text4`, `sa`.`text5` AS `shipping_text5`, `sa`.`text6` AS `shipping_text6`, `u`.*, `g`.`id` AS `preisgruppe`, `g`.`tax` AS `billing_net` FROM `s_order_billingaddress` AS `b` LEFT JOIN `s_order_shippingaddress` AS `s` ON `s`.`orderID` = `b`.`orderID` LEFT JOIN `s_user` AS `u` ON `b`.`userID` = `u`.`id` LEFT JOIN `s_user_addresses` AS `ub` ON `u`.`default_billing_address_id`=`ub`.`id` AND `u`.`id`=`ub`.`user_id` LEFT JOIN `s_core_countries` AS `bc` ON `bc`.`id` = `b`.`countryID` LEFT JOIN `s_core_countries` AS `sc` ON `sc`.`id` = `s`.`countryID` LEFT JOIN `s_core_customergroups` AS `g` ON `u`.`customergroup` = `g`.`groupkey` LEFT JOIN s_core_countries_areas bca ON bc.areaID = bca.id LEFT JOIN s_core_countries_areas sca ON sc.areaID = sca.id LEFT JOIN s_order_billingaddress_attributes ba ON b.id = ba.billingID LEFT JOIN s_order_shippingaddress_attributes sa ON s.id = sa.shippingID WHERE `b`.`orderID`=:orderId EOT; return $this->db->fetchRow($sql, ['orderId' => $orderId]); } /** * @return Enlight_Components_Session_Namespace */ private function getSession() { if ($this->session == null) { $this->session = Shopware()->Session(); } return $this->session; } /** * @return int */ private function getPaymentId() { if (!empty($this->sUserData['additional']['payment']['id'])) { return $this->sUserData['additional']['payment']['id']; } return $this->sUserData['additional']['user']['paymentID']; } /** * Helper function which returns the esd definition of the passed variant * order number. * Used for the sManageEsd function to check if the current order product variant * is an esd variant. * * @param string $orderNumber * * @return array|false */ private function getVariantEsd($orderNumber) { return $this->db->fetchRow( 'SELECT s_articles_esd.id AS id, serials FROM s_articles_esd, s_articles_details WHERE s_articles_esd.articleID = s_articles_details.articleID AND articledetailsID = s_articles_details.id AND s_articles_details.ordernumber= :orderNumber', [':orderNumber' => $orderNumber] ); } /** * Helper function which returns all available esd serials for the passed esd id. * * @param int $esdId * * @return array */ private function getAvailableSerialsOfEsd($esdId) { return $this->db->fetchAll( 'SELECT s_articles_esd_serials.id AS id, s_articles_esd_serials.serialnumber AS serialnumber FROM s_articles_esd_serials LEFT JOIN s_order_esd ON (s_articles_esd_serials.id = s_order_esd.serialID) WHERE s_order_esd.serialID IS NULL AND s_articles_esd_serials.esdID= :esdId', ['esdId' => $esdId] ); } /** * Checks if the passed transaction id is already set as transaction id of an * existing order. * * @param string|null $transactionId * * @return bool */ private function isTransactionExist($transactionId) { if (!\is_string($transactionId) || \strlen($transactionId) <= 3) { return false; } $insertOrder = $this->db->fetchRow( 'SELECT id FROM s_order WHERE transactionID = ? AND status != -1', [$transactionId] ); return !empty($insertOrder['id']); } /** * Checks if the current customer should see net prices. * * @param int $taxId * @param int $customerGroupId * * @return bool */ private function isTaxFree($taxId, $customerGroupId) { return ($this->config->get('sARTICLESOUTPUTNETTO') && !$taxId) || (!$taxId && $customerGroupId); } /** * Checks if the current order was send from a partner and returns * the partner code. * * @param int $userAffiliate Affiliate flag of the user data * * @return string|null */ private function getPartnerCode($userAffiliate) { $isPartner = $this->getSession()->offsetGet('sPartner'); if (!empty($isPartner)) { return $this->getSession()->offsetGet('sPartner'); } if (empty($userAffiliate)) { return null; } // Get Partner code return $this->db->fetchOne( 'SELECT idcode FROM s_emarketing_partner WHERE id = ?', [$userAffiliate] ); } /** * Helper function which reserves individual voucher codes for the * passed user. * * @param string $orderCode * @param int $customerId * @param int $voucherCodeId */ private function reserveVoucher($orderCode, $customerId, $voucherCodeId) { $getVoucher = $this->db->fetchRow( 'SELECT modus,id FROM s_emarketing_vouchers WHERE ordercode = ?', [$orderCode] ); if ($getVoucher['modus'] == CartPositionsMode::PREMIUM_PRODUCT) { $this->db->executeUpdate( 'UPDATE s_emarketing_voucher_codes SET cashed = 1, userID= ? WHERE id = ?', [$customerId, $voucherCodeId] ); } } /** * This function updates the data for an ordered variant. * The variant sales value will be increased by the passed quantity * and the variant stock value decreased by the passed quantity. * * @param string $orderNumber * @param int $quantity */ private function refreshOrderedVariant($orderNumber, $quantity) { $this->db->executeUpdate( 'UPDATE s_articles_details SET sales = sales + :quantity, instock = instock - :quantity WHERE ordernumber = :number', [':quantity' => $quantity, ':number' => $orderNumber] ); $this->eventManager->notify( 'product_stock_was_changed', ['number' => $orderNumber, 'quantity' => $quantity] ); } /** * Small helper function which iterates all basket rows * and formats the product name and order number. * This function is used for the order status mail. * * @return array */ private function getOrderDetailsForMail(array $basketRows) { $details = []; foreach ($basketRows as $content) { $content['articlename'] = trim(html_entity_decode($content['articlename'])); $content['articlename'] = str_replace(['
', '
'], "\n", $content['articlename']); $content['articlename'] = str_replace('€', '€', $content['articlename']); $content['articlename'] = trim($content['articlename']); while (strpos($content['articlename'], "\n\n") !== false) { $content['articlename'] = str_replace("\n\n", "\n", $content['articlename']); } $content['ordernumber'] = trim(html_entity_decode($content['ordernumber'] ?? '')); $details[] = $content; } return $details; } /** * Helper function which returns order details for the * order status mail. * Additionally to the order details rows, this function returns * the order detail attributes for each position. * * @param int $orderId * * @return array */ private function getOrderDetailsForStatusMail($orderId) { $orderDetails = $this->getOrderDetailsByOrderId($orderId); // add attributes to orderDetails foreach ($orderDetails as &$orderDetail) { $attributes = $this->attributeLoader->load('s_order_details_attributes', $orderDetail['orderdetailsID']); unset($attributes['id'], $attributes['detailID']); $orderDetail['attributes'] = $attributes; } return $orderDetails; } /** * Helper function which gets the formatted order data for the passed order id. * This function is used if the order status changed and the status mail will be * send. * * @param int $orderId */ private function getOrderForStatusMail($orderId) { $order = $this->getOrderById($orderId); $attributes = $this->attributeLoader->load('s_order_attributes', $orderId); unset($attributes['id'], $attributes['orderID']); $order['attributes'] = $attributes; return $order; } /** * Helper function which converts all HTML entities, in the passed user data array, * to their applicable characters. * * @return array */ private function getUserDataForMail(array $userData) { $userData['billingaddress'] = $this->htmlEntityDecodeRecursive($userData['billingaddress']); $userData['shippingaddress'] = $this->htmlEntityDecodeRecursive($userData['shippingaddress']); $userData['country'] = $this->htmlEntityDecodeRecursive($userData['country'] ?? null); $userData['additional']['payment']['description'] = html_entity_decode( $userData['additional']['payment']['description'] ); return $userData; } /** * Helper function to recursively apply html_entity_decode() to the given data. */ private function htmlEntityDecodeRecursive(?array $data): ?array { if ($data === null) { return null; } $func = static function ($item) use (&$func) { return \is_array($item) ? array_map($func, $item) : html_entity_decode((string) $item); }; return array_map($func, $data); } /** * Helper function for the sSaveOrder which formats a single * basket row. * This function sets the default for different properties, which * might not be set or invalid. * * @param array $basketRow * * @return array */ private function formatBasketRow($basketRow) { $basketRow['articlename'] = str_replace('
', "\n", $basketRow['articlename']); $basketRow['articlename'] = html_entity_decode($basketRow['articlename']); $basketRow['articlename'] = strip_tags($basketRow['articlename']); $basketRow['articlename'] = Shopware()->Modules()->Articles()->sOptimizeText( $basketRow['articlename'] ); if (empty($basketRow['price'])) { $basketRow['price'] = '0,00'; } if (empty($basketRow['esdarticle'])) { $basketRow['esdarticle'] = '0'; } if (empty($basketRow['modus'])) { $basketRow['modus'] = '0'; } if (empty($basketRow['taxID'])) { $basketRow['taxID'] = '0'; } if ($this->sNet) { $basketRow['taxID'] = '0'; } if (empty($basketRow['ean'])) { $basketRow['ean'] = ''; } if (empty($basketRow['releasedate'])) { $basketRow['releasedate'] = '0000-00-00'; } return $basketRow; } /** * Helper function which returns the current payment status * of the passed order. * * @param int $orderId * * @return string */ private function getOrderPaymentStatus($orderId) { return $this->db->fetchOne( 'SELECT `cleared` FROM `s_order` WHERE `id`=:orderId;', [':orderId' => $orderId] ); } /** * Helper function which returns the current order status of the passed order * id. * * @param int $orderId * * @return string */ private function getOrderStatus($orderId) { return $this->db->fetchOne( 'SELECT status FROM s_order WHERE id= :orderId;', [':orderId' => $orderId] ); } /** * @param string $orderNumber * @param string $email */ private function logOrderMailException(Exception $e, $orderNumber, $email) { $message = \sprintf( 'Could not send order mail for ordernumber %s to address %s', $orderNumber, $email ); $context = ['exception' => $e]; Shopware()->Container()->get('corelogger')->error($message, $context); } }