mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-12-26 14:40:29 +01:00
2329 lines
90 KiB
PHP
2329 lines
90 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Xentral\Modules\AmaInvoice\Service;
|
|
|
|
use Briefpapier;
|
|
use DateTime;
|
|
use GutschriftPDF;
|
|
use RechnungPDF;
|
|
use Xentral\Components\Database\Database;
|
|
use Xentral\Components\Filesystem\Adapter\FtpConfig;
|
|
use Xentral\Components\Filesystem\FilesystemFactory;
|
|
use \Application;
|
|
use Xentral\Components\Filesystem\FilesystemInterface;
|
|
use Xentral\Components\Filesystem\PathInfo;
|
|
use Xentral\Modules\AmaInvoice\Exception\AmazonInvoiceServiceException;
|
|
use Xentral\Modules\AmaInvoice\Exception\InvalidArgumentException;
|
|
use DateInterval;
|
|
use Xentral\Modules\AmaInvoice\Exception\ThrottlingException;
|
|
use \DateTimeInterface;
|
|
|
|
final class AmaInvoiceService
|
|
{
|
|
/** @var Database $db */
|
|
private $db;
|
|
|
|
/** @var Application $app */
|
|
private $app;
|
|
|
|
/** @var FilesystemFactory $filesystemFactory */
|
|
private $filesystemFactory;
|
|
|
|
/** @var FilesystemInterface $filesystem */
|
|
private $filesystem;
|
|
|
|
/** @var array $config */
|
|
private $config;
|
|
|
|
/** @var bool */
|
|
private $useFtp = false;
|
|
|
|
/**
|
|
* AmaInvoiceService constructor.
|
|
*
|
|
* @param Database $db
|
|
* @param FilesystemFactory $filesystemFactory
|
|
* @param Application $app
|
|
*/
|
|
public function __construct($db, $filesystemFactory, $app)
|
|
{
|
|
$this->db = $db;
|
|
$this->filesystemFactory = $filesystemFactory;
|
|
$this->app = $app;
|
|
}
|
|
|
|
/**
|
|
* @param string $startDate
|
|
* @param string $endDate
|
|
* @param string $type
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getDocumentsByApi($startDate, $endDate, $type = 'inv'): array
|
|
{
|
|
$response = $this->prepareParametersByXentral($startDate, $endDate, $type);
|
|
|
|
$response = @json_decode($response, true);
|
|
if (empty($response)) {
|
|
return [];
|
|
}
|
|
|
|
if (isset($response[0])) {
|
|
return $response;
|
|
}
|
|
if (isset($response['rem_gs_nr']) || isset($response['inv_rech_nr'])) {
|
|
return [$response];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* @param string $startDate
|
|
* @param string $endDate
|
|
* @param string $type
|
|
*
|
|
* @return string
|
|
*/
|
|
public function prepareParametersByXentral($startDate, $endDate, $type = 'inv'): string
|
|
{
|
|
$this->loadConfig();
|
|
$firmKeyId = $this->config['firmkeyid'];
|
|
$clientIdentifier = $this->config['clientidentifier'];
|
|
if (empty($firmKeyId)) {
|
|
throw new InvalidArgumentException('firmkeyid is empty');
|
|
}
|
|
if (empty($clientIdentifier)) {
|
|
throw new InvalidArgumentException('clientIdentifier is empty');
|
|
}
|
|
if (empty($startDate)) {
|
|
throw new InvalidArgumentException('startdate is empty');
|
|
}
|
|
if (empty($endDate)) {
|
|
throw new InvalidArgumentException('endDate is empty');
|
|
}
|
|
|
|
$startDate = date('Y-m-d', strtotime($startDate));
|
|
$endDate = date('Y-m-d', strtotime($endDate));
|
|
|
|
$now = new DateTime();
|
|
$beforeTwoMonths = clone $now;
|
|
$beforeTwoMonths->modify('-2 month');
|
|
|
|
if ($endDate >= $now->format('Y-m-d')) {
|
|
throw new InvalidArgumentException('endDate is not in the past');
|
|
}
|
|
if ($startDate < $beforeTwoMonths->format('Y-m-d')) {
|
|
throw new InvalidArgumentException('endDate is older than two months');
|
|
}
|
|
|
|
if ($type !== 'inv' && $type !== 'rem') {
|
|
throw new InvalidArgumentException('type must be "inv" or "rem"');
|
|
}
|
|
$serial = $this->app->erp->Firmendaten('lizenz');
|
|
if (empty($clientIdentifier)) {
|
|
throw new InvalidArgumentException('lizenz is empty');
|
|
}
|
|
$url = 'https://amazon.xentral.com/amainvoiceapp.php';
|
|
$schluessel = $this->app->erp->Firmendaten('schluessel');
|
|
if (empty($clientIdentifier)) {
|
|
throw new InvalidArgumentException('schluessel is empty');
|
|
}
|
|
$paras = [
|
|
'firm_key_id' => $firmKeyId,
|
|
'client_identifier' => $clientIdentifier,
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
'data_type' => $type,
|
|
'json' => false,
|
|
];
|
|
|
|
$paras = [
|
|
'serial' => $serial,
|
|
'schluessel' => $schluessel,
|
|
'paras' => json_encode($paras),
|
|
];
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($paras));
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
$response = curl_exec($ch);
|
|
$httpcode = curl_getinfo($ch);
|
|
curl_close($ch);
|
|
if ($response === 'Throttel is On') {
|
|
$this->db->perform(
|
|
"INSERT INTO `logfile` ( meldung, dump, module, action, bearbeiter, funktionsname, datum)
|
|
VALUES ('Throttel is On', '', 'amainvoice', '', 'Cronjob', '', NOW() )"
|
|
);
|
|
throw new ThrottlingException($response);
|
|
}
|
|
$httpcode = $httpcode['http_code'];
|
|
if (strpos((string)$httpcode, '2') === 0) {
|
|
if ($response === 'Error: Parameters not loaded [0]') {
|
|
throw new AmazonInvoiceServiceException($response);
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
if (!empty($response)) {
|
|
$response2 = @json_decode($response, true);
|
|
if (!empty($response2['error'])) {
|
|
if (!empty($response2['throttled'])) {
|
|
$error = $response2['error'];
|
|
if (is_array($error)) {
|
|
$error = reset($error);
|
|
}
|
|
$this->db->perform(
|
|
"INSERT INTO `logfile` ( meldung, dump, module, action, bearbeiter, funktionsname, datum)
|
|
VALUES ('Throttel by xentral is On', '', 'amainvoice', '', 'Cronjob', '', NOW() )"
|
|
);
|
|
throw new ThrottlingException($error);
|
|
}
|
|
if (is_array($response2['error'])) {
|
|
throw new AmazonInvoiceServiceException(reset($response2['error']));
|
|
}
|
|
if (is_string($response2['error'])) {
|
|
throw new AmazonInvoiceServiceException($response2['error']);
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new AmazonInvoiceServiceException($response);
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getConfig(): array
|
|
{
|
|
return $this->db->fetchPairs('SELECT `name`, `value` FROM `amainvoice_config`');
|
|
}
|
|
|
|
/**
|
|
* @param array $configArr
|
|
*/
|
|
public function setConfig($configArr): void
|
|
{
|
|
if (empty($configArr)) {
|
|
throw new InvalidArgumentException('Config Array empty');
|
|
}
|
|
|
|
foreach ($configArr as $key => $value) {
|
|
if (empty($key)) {
|
|
throw new InvalidArgumentException('Config Array invalid');
|
|
}
|
|
}
|
|
|
|
$config = $this->getConfig();
|
|
|
|
foreach ($configArr as $key => $value) {
|
|
if (!isset($config[$key])) {
|
|
$this->db->perform(
|
|
'INSERT INTO `amainvoice_config` (`name`, `value`) VALUES (:name, :value)',
|
|
['name' => $key, 'value' => (string)$value]
|
|
);
|
|
} elseif ((string)$value !== $config[$key]) {
|
|
$this->db->perform(
|
|
'UPDATE `amainvoice_config` SET `value` = :value WHERE `name` = :name',
|
|
['name' => $key, 'value' => (string)$value]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return array|PathInfo[]
|
|
*/
|
|
public function getFiles(): array
|
|
{
|
|
if ($this->config === null) {
|
|
$this->loadConfig();
|
|
}
|
|
if ($this->filesystem === null) {
|
|
try {
|
|
$now = new DateTime();
|
|
$beforeTwoMonths = clone $now;
|
|
$beforeTwoMonths->modify('-2 month');
|
|
$startDate = new DateTime($this->config['startdate']);
|
|
if ($startDate < $beforeTwoMonths) {
|
|
$startDate = $beforeTwoMonths;
|
|
}
|
|
$toDate = clone $now;
|
|
$toDate->sub(new DateInterval('P1D'));
|
|
$ret = [];
|
|
while ($startDate < $toDate) {
|
|
$dateFormated = $startDate->format('Y-m-d');
|
|
$ret[] = new PathInfo(
|
|
[
|
|
'type' => 'file',
|
|
'filename' => $dateFormated . '.inv',
|
|
'path' => $dateFormated . '.inv',
|
|
]
|
|
);
|
|
$ret[] = new PathInfo(
|
|
[
|
|
'type' => 'file',
|
|
'filename' => $dateFormated . '.rem',
|
|
'path' => $dateFormated . '.rem',
|
|
]
|
|
);
|
|
$startDate->add(new DateInterval('P1D'));
|
|
}
|
|
|
|
return $ret;
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
return $this->filesystem->listFiles('');
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function hasConfigFileSystem(): bool
|
|
{
|
|
if ($this->config === null) {
|
|
$this->loadConfig();
|
|
}
|
|
|
|
return $this->filesystem !== null;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getNewFiles(): array
|
|
{
|
|
$files = $this->getFiles();
|
|
if (empty($files)) {
|
|
return [];
|
|
}
|
|
|
|
$fileNames = [];
|
|
foreach ($files as $file) {
|
|
$fileName = $file->getPath();
|
|
$fileNames[] = $fileName;
|
|
}
|
|
|
|
$inDb = $this->db->fetchPairs(
|
|
'SELECT `id`, `filename` FROM `amainvoice_files` WHERE `filename` IN (:filenames)',
|
|
['filenames' => $fileNames]
|
|
);
|
|
|
|
$inDb = array_values($inDb);
|
|
|
|
return array_diff($fileNames, $inDb);
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
* @param string $to
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getFile($file, $to = ''): string
|
|
{
|
|
try {
|
|
if (empty($to)) {
|
|
$to = $file;
|
|
}
|
|
|
|
|
|
$fileSystemConfig = [
|
|
'permissions' => [
|
|
'file' => [
|
|
'public' => 0664,
|
|
'private' => 0664,
|
|
],
|
|
'dir' => [
|
|
'public' => 0775,
|
|
'private' => 0775,
|
|
],
|
|
],
|
|
];
|
|
if (is_file($this->app->erp->GetTMP() . $to)) {
|
|
return $this->app->erp->GetTMP() . $to;
|
|
}
|
|
$fileSystemTo = $this->filesystemFactory->createLocal($this->app->erp->GetTMP(), $fileSystemConfig);
|
|
|
|
if ($fileSystemTo->write($to, $this->filesystem->read($file))) {
|
|
return $this->app->erp->GetTMP() . $to;
|
|
};
|
|
} catch (\Exception $e) {
|
|
throw $e;
|
|
}
|
|
|
|
throw new InvalidArgumentException('could not download file ' . $file);
|
|
}
|
|
|
|
/**
|
|
* @param string $type
|
|
* @param string $amazonOrderId
|
|
* @param string $number
|
|
* @param array $datevRows
|
|
* @param array $positions
|
|
* @param string $pdfFile
|
|
* @param bool $createOrder
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function createDocument(
|
|
$type,
|
|
$amazonOrderId,
|
|
$number,
|
|
$datevRows,
|
|
$positions,
|
|
$pdfFile = '',
|
|
$createOrder = false
|
|
): bool {
|
|
if (empty($amazonOrderId)) {
|
|
throw new InvalidArgumentException('amazonOrderId is empty');
|
|
}
|
|
if ($number !== null && empty($number)) {
|
|
throw new InvalidArgumentException('document number is empty');
|
|
}
|
|
if ($type !== 'invoice' && $type !== 'returnorder') {
|
|
throw new InvalidArgumentException('type not valid');
|
|
}
|
|
$order = $this->db->fetchCol(
|
|
"SELECT `id`
|
|
FROM `auftrag`
|
|
WHERE `internet` = :amazonorderid AND `internet` <> '' AND `status` <> 'storniert' ",
|
|
['amazonorderid' => $amazonOrderId]
|
|
);
|
|
$firstOrderId = empty($order) ? null : reset($order);
|
|
$orderCreated = false;
|
|
$firstDatevRow = reset($datevRows);
|
|
$isOrderFbm = true;
|
|
if(!empty($firstDatevRow['fulfillmentchannel']) && $firstDatevRow['fulfillmentchannel'] === 'AFN') {
|
|
$isOrderFbm = false;
|
|
}
|
|
$statusInfo = null;
|
|
if($isOrderFbm) {
|
|
$statusInfo = $this->db->fetchRow(
|
|
"SELECT `status`, `schreibschutz`
|
|
FROM `auftrag`
|
|
WHERE `id` = :order_id ",
|
|
['order_id' => (int)$firstOrderId]
|
|
);
|
|
if(empty($statusInfo) || $statusInfo['status'] !== 'abgeschlossen') {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$billaddress1 = $firstDatevRow['billaddress1'];
|
|
$billaddress2 = $firstDatevRow['billaddress2'];
|
|
$billaddress3 = $firstDatevRow['billaddress3'];
|
|
$shipaddress1 = $firstDatevRow['shipaddress1'];
|
|
$shipaddress2 = $firstDatevRow['shipaddress2'];
|
|
$shipaddress3 = $firstDatevRow['shipaddress3'];
|
|
$billStreet3 = '';
|
|
$shipStreet3 = '';
|
|
if(!empty($billaddress1)) {
|
|
$billStreet = $billaddress1;
|
|
if(is_numeric($billaddress2)) {
|
|
$billStreet .= ' ' . $billaddress2;
|
|
$billStreet2 = $billaddress3;
|
|
}
|
|
else {
|
|
$billStreet2 = $billaddress2;
|
|
$billStreet3 = $billaddress3;
|
|
}
|
|
}
|
|
else {
|
|
$billStreet = $billaddress2;
|
|
if(is_numeric($billaddress3)) {
|
|
$billStreet .= ' ' . $billaddress3;
|
|
}
|
|
else {
|
|
$billStreet2 = $billaddress2;
|
|
}
|
|
}
|
|
if(!empty($shipaddress1)) {
|
|
$shipStreet = $shipaddress1;
|
|
if(is_numeric($shipaddress2)) {
|
|
$shipStreet .= ' ' . $shipaddress2;
|
|
$shipStreet2 = $shipaddress3;
|
|
}
|
|
else {
|
|
$shipStreet2 = $shipaddress2;
|
|
$shipStreet3 = $shipaddress3;
|
|
}
|
|
}
|
|
else {
|
|
$shipStreet = $shipaddress2;
|
|
if(is_numeric($shipaddress3)) {
|
|
$shipStreet .= ' ' . $shipaddress3;
|
|
}
|
|
else {
|
|
$shipStreet2 = $shipaddress2;
|
|
}
|
|
}
|
|
|
|
if (empty($order) && $createOrder) {
|
|
$address = [
|
|
'name' => $firstDatevRow['buyername'],
|
|
'kundennummer' => $this->app->erp->GetNextKundennummer(),
|
|
'strasse' => $billStreet,
|
|
'addresszusatz' => $billStreet2,
|
|
'ort' => $firstDatevRow['billcity'],
|
|
'plz' => $firstDatevRow['billpostalcode'],
|
|
'land' => $firstDatevRow['billcountry'],
|
|
];
|
|
$address['id'] = (int)$this->app->erp->InsertUpdateAdresse($address);
|
|
$orderId = (int)$this->app->erp->CreateAuftrag($address['id']);
|
|
$this->app->erp->LoadAuftragStandardwerte($orderId, $address['id']);
|
|
$order = [
|
|
'name' => $firstDatevRow['buyername'],
|
|
'strasse' => $billStreet,
|
|
'addresszusatz' => $billStreet2,
|
|
'ort' => $firstDatevRow['billcity'],
|
|
'plz' => $firstDatevRow['billpostalcode'],
|
|
'land' => $firstDatevRow['billcountry'],
|
|
'email' => $firstDatevRow['buyeremail'],
|
|
'lieferstrasse' => $shipStreet,
|
|
'lieferaddresszusatz' => $shipStreet2,
|
|
'lieferland' => $firstDatevRow['shipcountry'],
|
|
'versandart' => $firstDatevRow['carrier'],
|
|
'lieferort' => $firstDatevRow['shipcity'],
|
|
'lieferplz' => $firstDatevRow['shippostalcode'],
|
|
'liefername' => $firstDatevRow['recipientname'],
|
|
];
|
|
if ($isOrderFbm && !empty($this->config['projectfbm'])) {
|
|
$order['projekt'] = $this->config['projectfbm'];
|
|
} elseif (!$isOrderFbm && !empty($this->config['projectfba'])) {
|
|
$order['projekt'] = $this->config['projectfba'];
|
|
}
|
|
if (!empty($this->config['paymentmethod'])) {
|
|
$order['versandart'] = $this->config['paymentmethod'];
|
|
}
|
|
$this->app->DB->UpdateArr('auftrag', $orderId, 'id', $order, true);
|
|
$this->db->perform(
|
|
'UPDATE `auftrag` SET `internet` = :orderid WHERE `id` = :id',
|
|
[
|
|
'orderid' => $amazonOrderId,
|
|
'id' => $orderId,
|
|
]
|
|
);
|
|
$this->app->erp->BelegFreigabe('auftrag', $orderId);
|
|
$orderCreated = true;
|
|
$order = $this->db->fetchCol(
|
|
"SELECT `id`
|
|
FROM `auftrag`
|
|
WHERE `internet` = :amazonorderid AND `internet` <> '' AND `status` <> 'storniert' ",
|
|
['amazonorderid' => $amazonOrderId]
|
|
);
|
|
$this->app->erp->AuftragProtokoll($orderId, 'Auftrag erstellt durch AmaInvoice');
|
|
}
|
|
|
|
if (empty($order)) {
|
|
return false;
|
|
//throw new InvalidArgumentException(sprintf('order %s not found', $amazonOrderId));
|
|
}
|
|
$order = (int)reset($order);
|
|
|
|
if ($type === 'invoice') {
|
|
if ($number !== null) {
|
|
$invoice = $this->db->fetchCol(
|
|
'SELECT `id` FROM `rechnung` WHERE `auftragid` = :orderid AND `belegnr` = :number',
|
|
['orderid' => $order, 'number' => $number]
|
|
);
|
|
} else {
|
|
$invoice = $this->db->fetchCol(
|
|
'SELECT `id` FROM `rechnung` WHERE `auftragid` = :orderid',
|
|
['orderid' => $order]
|
|
);
|
|
}
|
|
if (!empty($invoice)) {
|
|
return false;
|
|
}
|
|
$forceApproval = $this->app->erp->Firmendaten('schnellanlegen_ohnefreigabe') == '1';
|
|
if($forceApproval) {
|
|
$db = $this->app->Conf->WFdbname;
|
|
$this->app->erp->firmendaten[$db]['schnellanlegen_ohnefreigabe'] = 0;
|
|
}
|
|
$invoice = (int)$this->app->erp->WeiterfuehrenAuftragZuRechnung($order);
|
|
if($isOrderFbm && !empty($statusInfo)) {
|
|
$this->db->perform(
|
|
'UPDATE `auftrag` SET `status` = :status, `schreibschutz` = :readonly WHERE `id` = :order_id',
|
|
[
|
|
'status' => $statusInfo['status'],
|
|
'readonly' => (int)$statusInfo['schreibschutz'],
|
|
'order_id' => $order
|
|
]
|
|
);
|
|
}
|
|
if($forceApproval) {
|
|
$this->app->erp->firmendaten[$db]['schnellanlegen_ohnefreigabe'] = '1';
|
|
}
|
|
$invoiceArr = [
|
|
'name' => $firstDatevRow['buyername'],
|
|
'strasse' => $billStreet,
|
|
'addresszusatz' => $billStreet2,
|
|
'abteilung' => $billStreet3,
|
|
'ort' => $firstDatevRow['billcity'],
|
|
'plz' => $firstDatevRow['billpostalcode'],
|
|
'land' => $firstDatevRow['billcountry'],
|
|
'email' => $firstDatevRow['buyeremail'],
|
|
'belegnr' => $number === null ? $firstDatevRow['inv_rech_nr'] : $number,
|
|
];
|
|
|
|
$orderArr = [
|
|
'name' => $firstDatevRow['buyername'],
|
|
'strasse' => $billStreet,
|
|
'addresszusatz' => $billStreet2,
|
|
'abteilung' => $billStreet3,
|
|
'ort' => $firstDatevRow['billcity'],
|
|
'plz' => $firstDatevRow['billpostalcode'],
|
|
'land' => $firstDatevRow['billcountry'],
|
|
'email' => $firstDatevRow['buyeremail'],
|
|
];
|
|
if(
|
|
$firstDatevRow['buyername'] !== $firstDatevRow['recipientname']
|
|
|| $billStreet !== $shipStreet
|
|
|| $billStreet2 !== $shipStreet2
|
|
) {
|
|
$orderArr['abweichendelieferadresse'] = 1;
|
|
$orderArr['liefername'] = $firstDatevRow['recipientname'];
|
|
$orderArr['lieferstrasse'] = $shipStreet;
|
|
$orderArr['lieferadresszusatz'] = $shipStreet2;
|
|
$orderArr['lieferabteilung'] = $shipStreet3;
|
|
$orderArr['lieferort'] = $firstDatevRow['shipcity'];
|
|
$orderArr['lieferplz'] = $firstDatevRow['shippostalcode'];
|
|
$orderArr['lieferland'] = $firstDatevRow['shipcountry'];
|
|
}
|
|
$this->app->DB->UpdateArr('auftrag', $order, 'id', $orderArr, true);
|
|
$this->app->DB->UpdateArr('rechnung', $invoice, 'id', $invoiceArr, true);
|
|
$this->app->erp->AuftragProtokoll($order, 'Rechnung erstellt durch AmaInvoice');
|
|
$this->app->erp->BelegFreigabe('rechnung', $invoice);
|
|
|
|
|
|
$soll = 0;
|
|
foreach ($positions as $position) {
|
|
$soll += (float)str_replace(',', '.', $position['brutto_total']);
|
|
}
|
|
|
|
$this->addPositions('invoice', $invoice, $positions, $orderCreated ? $order : null);
|
|
$this->addDiscountArticles(
|
|
'invoice',
|
|
$invoice,
|
|
$datevRows,
|
|
$positions,
|
|
$orderCreated ? $order : null
|
|
);
|
|
$this->addShippingArticles(
|
|
'invoice',
|
|
$invoice,
|
|
$datevRows,
|
|
$positions,
|
|
$orderCreated ? $order : null
|
|
);
|
|
$this->app->erp->RechnungNeuberechnen($invoice);
|
|
|
|
$this->db->perform(
|
|
"UPDATE `rechnung`
|
|
SET `datum` = :date, `waehrung` = :currency, `soll` = :soll, `extsoll` = :soll,
|
|
schreibschutz = 1, `status` = 'versendet'
|
|
WHERE `id` = :invoiceId",
|
|
[
|
|
'date' => $firstDatevRow['date'],
|
|
'currency' => $firstDatevRow['currency'],
|
|
'invoiceId' => $invoice,
|
|
'soll' => $soll,
|
|
]
|
|
);
|
|
if(!empty($firstDatevRow['fulfillmentchannel']) && $firstDatevRow['fulfillmentchannel'] === 'AFN') {
|
|
$this->db->perform(
|
|
'UPDATE `rechnung` SET `ist` = `soll` WHERE `id` = :invoiceId',
|
|
[
|
|
'invoiceId' => $invoice,
|
|
]
|
|
);
|
|
}
|
|
|
|
$this->app->erp->PDFArchivieren('rechnung', $invoice, true);
|
|
if (empty($pdfFile) && !empty($firstDatevRow['documentlink'])) {
|
|
$content = file_get_contents($firstDatevRow['documentlink']);
|
|
$pdfFile = basename($firstDatevRow['documentlink']) . '.pdf';
|
|
file_put_contents($this->app->erp->GetTMP() . $pdfFile, $content);
|
|
$this->archiveDocument('invoice', $invoice, $pdfFile);
|
|
if (is_file($this->app->erp->GetTMP() . $pdfFile)) {
|
|
unlink($this->app->erp->GetTMP() . $pdfFile);
|
|
}
|
|
} elseif (!empty($pdfFile)) {
|
|
$this->archiveDocument('invoice', $invoice, $pdfFile);
|
|
}
|
|
|
|
if ($orderCreated && !$isOrderFbm) {
|
|
$this->db->perform(
|
|
"UPDATE `auftrag`
|
|
SET `datum` = :date, `waehrung` = :currency, `gesamtsumme` = :soll, `extsoll` = :soll,
|
|
schreibschutz = 1, `status` = 'abgeschlossen'
|
|
WHERE `id` = :orderId",
|
|
[
|
|
'date' => $firstDatevRow['date'],
|
|
'currency' => $firstDatevRow['currency'],
|
|
'orderId' => $order,
|
|
'soll' => $soll,
|
|
]
|
|
);
|
|
|
|
$this->app->erp->PDFArchivieren('auftrag', $order, true);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
if ($type === 'returnorder') {
|
|
$invoices = $this->db->fetchCol(
|
|
'SELECT `id` FROM `rechnung` WHERE `auftragid` = :orderid',
|
|
['orderid' => $order]
|
|
);
|
|
if (empty($invoices)) {
|
|
throw new InvalidArgumentException('invoice not found');
|
|
}
|
|
$returnOrder = $this->db->fetchCol(
|
|
'SELECT `id` FROM `gutschrift` WHERE `rechnungid` IN (:invoiceids) AND `belegnr` = :number',
|
|
['invoiceids' => $invoices, 'number' => $number]
|
|
);
|
|
|
|
if (!empty($returnOrder)) {
|
|
return false;
|
|
}
|
|
|
|
$invoice = reset($invoices);
|
|
$forceApproval = $this->app->erp->Firmendaten('schnellanlegen_ohnefreigabe') == '1';
|
|
if($forceApproval) {
|
|
$db = $this->app->Conf->WFdbname;
|
|
$this->app->erp->firmendaten[$db]['schnellanlegen_ohnefreigabe'] = 0;
|
|
}
|
|
$returnOrder = $this->app->erp->WeiterfuehrenRechnungZuGutschrift($invoice);
|
|
if($forceApproval) {
|
|
$this->app->erp->firmendaten[$db]['schnellanlegen_ohnefreigabe'] = 1;
|
|
}
|
|
$this->app->erp->RechnungProtokoll($invoice, 'Gutschrift erstellt durch AmaInvoice');
|
|
$this->db->perform(
|
|
'UPDATE `gutschrift` SET `belegnr` = :number WHERE `id` = :id LIMIT 1',
|
|
[
|
|
'number' => (string)$number,
|
|
'id' => (int)$returnOrder,
|
|
]
|
|
);
|
|
$this->app->erp->BelegFreigabe('gutschrift', $returnOrder);
|
|
|
|
$soll = 0;
|
|
foreach ($datevRows as $datevRow) {
|
|
$soll += (float)str_replace(',', '.', $datevRow['brutto']);
|
|
}
|
|
|
|
$this->addPositions('returnorder', $returnOrder, $positions);
|
|
$this->addDiscountArticles('returnorder', $returnOrder, $datevRows, $positions);
|
|
$this->addShippingArticles('returnorder', $returnOrder, $datevRows, $positions);
|
|
$this->app->erp->GutschriftNeuberechnen($returnOrder);
|
|
$this->db->perform(
|
|
"UPDATE `gutschrift`
|
|
SET `datum` = :date, `waehrung` = :currency, `soll` = :soll, `extsoll` = :soll,
|
|
schreibschutz = 1, `status` = 'versendet'
|
|
WHERE `id` = :returnorderid",
|
|
[
|
|
'date' => $firstDatevRow['date'],
|
|
'currency' => $firstDatevRow['currency'],
|
|
'returnorderid' => $returnOrder,
|
|
'soll' => $soll,
|
|
]
|
|
);
|
|
$this->app->erp->PDFArchivieren('gutschrift', $returnOrder, true);
|
|
if (empty($pdfFile) && !empty($firstDatevRow['documentlink'])) {
|
|
$content = file_get_contents($firstDatevRow['documentlink']);
|
|
$pdfFile = basename($firstDatevRow['documentlink']) . '.pdf';
|
|
file_put_contents($this->app->erp->GetTMP() . $pdfFile, $content);
|
|
$this->archiveDocument('returnorder', $returnOrder, $pdfFile);
|
|
if (is_file($this->app->erp->GetTMP() . $pdfFile)) {
|
|
unlink($this->app->erp->GetTMP() . $pdfFile);
|
|
}
|
|
} elseif (!empty($pdfFile)) {
|
|
$this->archiveDocument('returnorder', $returnOrder, $pdfFile);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
* @param string $type
|
|
* @param string $status
|
|
*/
|
|
public function markFile($file, $type, $status = ''): void
|
|
{
|
|
$this->db->perform(
|
|
'INSERT INTO `amainvoice_files` (`filename`, `type`, `status`) VALUES (:filename, :type, :status)',
|
|
['filename' => $file, 'type' => $type, 'status' => (string)$status]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
*/
|
|
public function cleanFile($file): void
|
|
{
|
|
$file = $this->app->erp->GetTMP() . $file;
|
|
if (!is_file($file)) {
|
|
return;
|
|
}
|
|
@unlink($file);
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPositionFromDatevCsv($file): array
|
|
{
|
|
$handle = fopen($file, 'rb');
|
|
if (empty($handle)) {
|
|
throw new InvalidArgumentException('could not open file ' . $file);
|
|
}
|
|
|
|
$firstLine = fgetcsv($handle, 0, ';');
|
|
$from = $firstLine[14];
|
|
$year = substr($from, 0, 4);
|
|
$return = [];
|
|
while ($row = fgetcsv($handle, 0, ';')) {
|
|
$brutto = $row[0];
|
|
$soll = $row[1] === 'S';
|
|
$currency = $row[2];
|
|
$exchangerate = $row[3];
|
|
$konto = $row[6];
|
|
$gegenkonto = $row[7];
|
|
$bu = $row[8];
|
|
$date = $row[9];
|
|
if (strlen($date) < 4) {
|
|
$date = '0' . $date;
|
|
}
|
|
$day = substr($date, 0, 2);
|
|
$month = substr($date, 2, 2);
|
|
$date = $year . '-' . $month . '-' . $day;
|
|
$number = $row[10];
|
|
$amzOrderId = $row[52];
|
|
$marketplace = $row[50];
|
|
$ustId = $row[48];
|
|
$tax = $row[40];
|
|
$euCountry = $row[39];
|
|
$customerUstId = $row[58];
|
|
$storageCountry = $row[54];
|
|
$country = $row[56];
|
|
$type = $soll ? 'invoice' : 'returnorder';
|
|
if (strpos($number, 'GS') === 0) {
|
|
$type = 'returnorder';
|
|
}
|
|
$return[$type][$amzOrderId][$number] = [
|
|
'brutto' => $brutto,
|
|
'currency' => $currency,
|
|
'exchangerate' => $exchangerate,
|
|
'konto' => $konto,
|
|
'gegenkonto' => $gegenkonto,
|
|
'bu' => $bu,
|
|
'date' => $date,
|
|
'marketplace' => $marketplace,
|
|
'eucountry' => $euCountry,
|
|
'tax' => $tax,
|
|
'ustid' => $ustId,
|
|
'customerustid' => $customerUstId,
|
|
'storageCountry' => $storageCountry,
|
|
'country' => $country,
|
|
];
|
|
}
|
|
fclose($handle);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
*/
|
|
public function executeImportDateFile($file)
|
|
{
|
|
$ext = substr($file, -3);
|
|
$type = $ext === 'rem' ? 'returnorder' : 'invoice';
|
|
$apiPositions = $this->executeGetPostionsByApiAndFilename($file);
|
|
foreach ($apiPositions[$type] as $amazonOrderId => $apiSubPositions) {
|
|
$document = [$apiSubPositions['document']];
|
|
foreach ($apiSubPositions['positions'] as $numberInvoice => $apiSubPosition) {
|
|
try {
|
|
$this->createDocument(
|
|
$type,
|
|
$amazonOrderId,
|
|
null,
|
|
$document,
|
|
$apiSubPosition,
|
|
'',
|
|
$this->isCreateOrderActive()
|
|
);
|
|
} catch (InvalidArgumentException $e) {
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->markFile($file, 'api_' . $type, 'imported');
|
|
}
|
|
|
|
/**
|
|
* @param bool $isReturnOrder
|
|
* @param bool $createOrder
|
|
*/
|
|
public function executeImportDateDbEntries($isReturnOrder, $createOrder = false): void
|
|
{
|
|
$apiPositions = $this->getNotImportedPositionsFromDb($isReturnOrder, $createOrder);
|
|
$type = $isReturnOrder ? 'returnorder' : 'invoice';
|
|
foreach ($apiPositions[$type] as $amazonOrderId => $apiSubPositions) {
|
|
$document = [$apiSubPositions['document']];
|
|
foreach ($apiSubPositions['positions'] as $numberInvoice => $apiSubPosition) {
|
|
try {
|
|
$this->createDocument(
|
|
$type,
|
|
$amazonOrderId,
|
|
null,
|
|
$document,
|
|
$apiSubPosition,
|
|
'',
|
|
$createOrder
|
|
);
|
|
} catch (InvalidArgumentException $e) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param DateTimeInterface $dateFrom
|
|
* @param DateTimeInterface $dateTo
|
|
* @param bool $isReturnOrder
|
|
*/
|
|
public function markDbEntriesToImport($dateFrom, $dateTo, $isReturnOrder): void
|
|
{
|
|
if (!$isReturnOrder) {
|
|
$this->loadConfig();
|
|
$createOrder = $this->isCreateOrderActive();
|
|
if (!$createOrder) {
|
|
$this->db->perform(
|
|
"UPDATE `amazoninvoice_position`
|
|
SET `create` = 1
|
|
WHERE `doctype_id` = 0 AND `create_order` = 0 AND `rem_gs_nr` = ''
|
|
AND `inv_date` >= :dateFrom AND `inv_date` >= :dateTo",
|
|
[
|
|
'dateFrom' => $dateFrom->format('Y-m-d'),
|
|
'dateTo' => $dateTo->format('Y-m-d'),
|
|
]
|
|
);
|
|
} else {
|
|
$this->db->perform(
|
|
"UPDATE `amazoninvoice_position`
|
|
SET `create` = 1, `create_order` = 1
|
|
WHERE `doctype_id` = 0 AND `create_order` = 0 AND `rem_gs_nr` = ''
|
|
AND `inv_date` >= :dateFrom AND `inv_date` >= :dateTo",
|
|
[
|
|
'dateFrom' => $dateFrom->format('Y-m-d'),
|
|
'dateTo' => $dateTo->format('Y-m-d'),
|
|
]
|
|
);
|
|
}
|
|
} else {
|
|
$this->db->perform(
|
|
"UPDATE `amazoninvoice_position`
|
|
SET `create` = 1
|
|
WHERE `doctype_id` = 0 AND `create_order` = 0 AND `rem_gs_nr` <> ''
|
|
AND `rem_gs_nr` >= :dateFrom AND `rem_gs_nr` >= :dateTo",
|
|
[
|
|
'dateFrom' => $dateFrom->format('Y-m-d'),
|
|
'dateTo' => $dateTo->format('Y-m-d'),
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
*
|
|
* @return array|array[]
|
|
*/
|
|
public function executeGetPostionsByApiAndFilename($file): array
|
|
{
|
|
$date = substr($file, 0, 10);
|
|
$ext = substr($file, -3);
|
|
|
|
$arr = $this->getDocumentsByApi($date, $date, $ext);
|
|
$arr = $this->insertFromApiReturn($arr, $date, $ext === 'rem');
|
|
|
|
return $this->getPositionsFromApiRequest(
|
|
$arr,
|
|
$ext === 'rem'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param bool $isReturnOrder
|
|
* @param bool $createOrder
|
|
*
|
|
* @return array|array[]
|
|
*/
|
|
public function getNotImportedPositionsFromDb($isReturnOrder, $createOrder = false, $hours = 8): array
|
|
{
|
|
if (!$isReturnOrder) {
|
|
if (!$createOrder) {
|
|
$arr = $this->db->fetchAll(
|
|
"SELECT ap.*
|
|
FROM `amazoninvoice_position` AS `ap`
|
|
WHERE ap.`create` = 1 AND ap.doctype_id = 0 AND `create_order` = 0 AND ap.rem_gs_nr = ''
|
|
ORDER BY ap.`inv_date`, ap.id"
|
|
);
|
|
} else {
|
|
$arr = $this->db->fetchAll(
|
|
"SELECT ap.*
|
|
FROM `amazoninvoice_position` AS `ap`
|
|
WHERE ap.`create` = 1 AND ap.doctype_id = 0 AND `create_order` = 1 AND ap.rem_gs_nr = ''
|
|
AND ap.created_at < DATE_SUB(NOW(), INTERVAL :hours HOUR)
|
|
ORDER BY ap.`inv_date`, ap.id",
|
|
[
|
|
'hours' => $hours,
|
|
]
|
|
);
|
|
}
|
|
} else {
|
|
$arr = $this->db->fetchAll(
|
|
"SELECT ap.*
|
|
FROM `amazoninvoice_position` AS `ap`
|
|
WHERE ap.`create` = 1 AND ap.doctype_id = 0 AND ap.rem_gs_nr <> ''
|
|
ORDER BY ap.`rem_date`, ap.id"
|
|
);
|
|
}
|
|
|
|
return $this->getPositionsFromApiRequest(
|
|
$arr,
|
|
$isReturnOrder
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array $arr
|
|
* @param string $date
|
|
* @param bool $isReturnOrder
|
|
*
|
|
* @return array
|
|
*/
|
|
public function insertFromApiReturn($arr, $date, $isReturnOrder): array
|
|
{
|
|
if ($isReturnOrder) {
|
|
$inDb = $this->db->fetchPairs(
|
|
'SELECT `rem_gs_nr`, `id` FROM `amazoninvoice_position` WHERE `rem_date` = :date',
|
|
['date' => $date]
|
|
);
|
|
} else {
|
|
$inDb = $this->db->fetchPairs(
|
|
'SELECT `inv_rech_nr`, `id` FROM `amazoninvoice_position` WHERE `inv_date` = :date',
|
|
['date' => $date]
|
|
);
|
|
}
|
|
foreach ($arr as $key => $row) {
|
|
if ($isReturnOrder) {
|
|
if (!empty($inDb[$row['rem_gs_nr']])) {
|
|
$arr[$key]['id'] = $inDb[$row['rem_gs_nr']];
|
|
continue;
|
|
}
|
|
} elseif (!empty($inDb[$row['inv_rech_nr']])) {
|
|
$arr[$key]['id'] = $inDb[$row['inv_rech_nr']];
|
|
continue;
|
|
}
|
|
|
|
$this->db->perform(
|
|
'INSERT INTO `amazoninvoice_position`
|
|
(
|
|
`inv_rech_nr`,`inv_date`,`amazonorderid`,`shipmentdate`,`buyeremail`,`buyerphonenumber`,
|
|
`buyername`,`sku`,`productname`,`quantitypurchased`,`quantityshipped`,`currency`,`mwst`,
|
|
`taxrate`,`brutto_total`,`netto_total`,`tax_total`,`itemprice`,`itemprice_netto`,`itemprice_tax`,
|
|
`shippingprice`,`shippingprice_netto`,`shippingprice_tax`,`giftwrapprice`,`giftwrapprice_netto`,
|
|
`giftwrapprice_tax`,`itempromotiondiscount`,`itempromotiondiscount_netto`,
|
|
`itempromotiondiscount_tax`,`shippromotiondiscount`,`shippromotiondiscount_netto`,
|
|
`shippromotiondiscount_tax`,`giftwrappromotiondiscount`,`giftwrappromotiondiscount_netto`,
|
|
`giftwrappromotiondiscount_tax`,`shipservicelevel`,`recipientname`,`shipaddress1`,`shipaddress2`,
|
|
`shipaddress3`,`shipcity`,`shipstate`,`shippostalcode`,`shipcountry`,`shipphonenumber`,
|
|
`billaddress1`,`billaddress2`,`billaddress3`,`billcity`,`billstate`,`billpostalcode`,
|
|
`billcountry`,`carrier`,`trackingnumber`,`fulfillmentcenterid`,`fulfillmentchannel`,
|
|
`saleschannel`,`asin`,`conditiontype`,`quantityavailable`,`isbusinessorder`,`uid`,`vatcheck`,
|
|
`documentlink`,`order_id`,`rem_gs_nr`,`orderid`,
|
|
`rem_date`,`returndate`,`buyercompanyname`,`quantity`,`remreturnshipcost`,
|
|
`remsondererstattung`,`itempromotionid`,`reason`,`rem_gs_nr_real`, `created_at`
|
|
) VALUES (
|
|
:inv_rech_nr, :inv_date, :amazonorderid, :shipmentdate, :buyeremail, :buyerphonenumber,
|
|
:buyername, :sku, :productname, :quantitypurchased, :quantityshipped, :currency, :mwst,
|
|
:taxrate, :brutto_total, :netto_total, :tax_total, :itemprice, :itemprice_netto, :itemprice_tax,
|
|
:shippingprice, :shippingprice_netto, :shippingprice_tax, :giftwrapprice, :giftwrapprice_netto,
|
|
:giftwrapprice_tax, :itempromotiondiscount, :itempromotiondiscount_netto,
|
|
:itempromotiondiscount_tax, :shippromotiondiscount, :shippromotiondiscount_netto,
|
|
:shippromotiondiscount_tax, :giftwrappromotiondiscount, :giftwrappromotiondiscount_netto,
|
|
:giftwrappromotiondiscount_tax, :shipservicelevel, :recipientname, :shipaddress1,
|
|
:shipaddress2, :shipaddress3, :shipcity, :shipstate, :shippostalcode, :shipcountry,
|
|
:shipphonenumber, :billaddress1, :billaddress2, :billaddress3, :billcity, :billstate,
|
|
:billpostalcode, :billcountry, :carrier, :trackingnumber, :fulfillmentcenterid,
|
|
:fulfillmentchannel, :saleschannel, :asin, :conditiontype, :quantityavailable,
|
|
:isbusinessorder, :uid, :vatcheck, :documentlink, :order_id, :rem_gs_nr, :orderid,
|
|
:rem_date, :returndate, :buyercompanyname, :quantity, :remreturnshipcost,
|
|
:remsondererstattung, :itempromotionid, :reason, :rem_gs_nr_real, NOW()
|
|
) ',
|
|
[
|
|
'inv_rech_nr' => (string)$row['inv_rech_nr'],
|
|
'inv_date' => (string)$row['inv_date'],
|
|
'amazonorderid' => (string)$row['amazonorderid'],
|
|
'shipmentdate' => (string)$row['shipmentdate'],
|
|
'buyeremail' => (string)$row['buyeremail'],
|
|
'buyerphonenumber' => (string)$row['buyerphonenumber'],
|
|
'buyername' => (string)$row['buyername'],
|
|
'sku' => (string)$row['sku'],
|
|
'productname' => (string)$row['productname'],
|
|
'quantitypurchased' => (string)$row['quantitypurchased'],
|
|
'quantityshipped' => (string)$row['quantityshipped'],
|
|
'currency' => (string)$row['currency'],
|
|
'mwst' => (string)$row['mwst'],
|
|
'taxrate' => (string)$row['taxrate'],
|
|
'brutto_total' => (string)$row['brutto_total'],
|
|
'netto_total' => (string)$row['netto_total'],
|
|
'tax_total' => (string)$row['tax_total'],
|
|
'itemprice' => (string)$row['itemprice'],
|
|
'itemprice_netto' => (string)$row['itemprice_netto'],
|
|
'itemprice_tax' => (string)$row['itemprice_tax'],
|
|
'shippingprice' => (string)$row['shippingprice'],
|
|
'shippingprice_netto' => (string)$row['shippingprice_netto'],
|
|
'shippingprice_tax' => (string)$row['shippingprice_tax'],
|
|
'giftwrapprice' => (string)$row['giftwrapprice'],
|
|
'giftwrapprice_netto' => (string)$row['giftwrapprice_netto'],
|
|
'giftwrapprice_tax' => (string)$row['giftwrapprice_tax'],
|
|
'itempromotiondiscount' => (string)$row['itempromotiondiscount'],
|
|
'itempromotiondiscount_netto' => (string)$row['itempromotiondiscount_netto'],
|
|
'itempromotiondiscount_tax' => (string)$row['itempromotiondiscount_tax'],
|
|
'shippromotiondiscount' => (string)$row['shippromotiondiscount'],
|
|
'shippromotiondiscount_netto' => (string)$row['shippromotiondiscount_netto'],
|
|
'shippromotiondiscount_tax' => (string)$row['shippromotiondiscount_tax'],
|
|
'giftwrappromotiondiscount' => (string)$row['giftwrappromotiondiscount'],
|
|
'giftwrappromotiondiscount_netto' => (string)$row['giftwrappromotiondiscount_netto'],
|
|
'giftwrappromotiondiscount_tax' => (string)$row['giftwrappromotiondiscount_tax'],
|
|
'shipservicelevel' => (string)$row['shipservicelevel'],
|
|
'recipientname' => (string)$row['recipientname'],
|
|
'shipaddress1' => (string)$row['shipaddress1'],
|
|
'shipaddress2' => (string)$row['shipaddress2'],
|
|
'shipaddress3' => (string)$row['shipaddress3'],
|
|
'shipcity' => (string)$row['shipcity'],
|
|
'shipstate' => (string)$row['shipstate'],
|
|
'shippostalcode' => (string)$row['shippostalcode'],
|
|
'shipcountry' => (string)$row['shipcountry'],
|
|
'shipphonenumber' => (string)$row['shipphonenumber'],
|
|
'billaddress1' => (string)$row['billaddress1'],
|
|
'billaddress2' => (string)$row['billaddress2'],
|
|
'billaddress3' => (string)$row['billaddress3'],
|
|
'billcity' => (string)$row['billcity'],
|
|
'billstate' => (string)$row['billstate'],
|
|
'billpostalcode' => (string)$row['billpostalcode'],
|
|
'billcountry' => (string)$row['billcountry'],
|
|
'carrier' => (string)$row['carrier'],
|
|
'trackingnumber' => (string)$row['trackingnumber'],
|
|
'fulfillmentcenterid' => (string)$row['fulfillmentcenterid'],
|
|
'fulfillmentchannel' => (string)$row['fulfillmentchannel'],
|
|
'saleschannel' => (string)$row['saleschannel'],
|
|
'asin' => (string)$row['asin'],
|
|
'conditiontype' => (string)$row['conditiontype'],
|
|
'quantityavailable' => (string)$row['quantityavailable'],
|
|
'isbusinessorder' => (string)$row['isbusinessorder'],
|
|
'uid' => (string)$row['uid'],
|
|
'vatcheck' => (string)$row['vatcheck'],
|
|
'documentlink' => (string)$row['documentlink'],
|
|
'order_id' => (string)$row['order_id'],
|
|
'rem_gs_nr' => (string)$row['rem_gs_nr'],
|
|
'orderid' => (string)$row['orderid'],
|
|
'rem_date' => (string)$row['rem_date'],
|
|
'returndate' => (string)$row['returndate'],
|
|
'buyercompanyname' => (string)$row['buyercompanyname'],
|
|
'quantity' => (string)$row['quantity'],
|
|
'remreturnshipcost' => (string)$row['remreturnshipcost'],
|
|
'remsondererstattung' => (string)$row['remsondererstattung'],
|
|
'itempromotionid' => (string)$row['itempromotionid'],
|
|
'reason' => (string)$row['reason'],
|
|
'rem_gs_nr_real' => (string)$row['rem_gs_nr_real'],
|
|
]
|
|
);
|
|
|
|
$arr[$key]['id'] = $this->db->lastInsertId();
|
|
}
|
|
|
|
return $arr;
|
|
}
|
|
|
|
/**
|
|
* @param array $arr
|
|
* @param bool $isReturnOrder
|
|
*
|
|
* @return array|array[]
|
|
*/
|
|
public function getPositionsFromApiRequest($arr, $isReturnOrder = false): array
|
|
{
|
|
if (empty($arr)) {
|
|
return [];
|
|
}
|
|
$type = $isReturnOrder ? 'returnorder' : 'invoice';
|
|
$return = [$type => []];
|
|
$numberKey = $isReturnOrder ? 'rem_gs_nr' : 'inv_rech_nr';
|
|
$dateKey = $isReturnOrder ? 'rem_date' : 'inv_date';
|
|
|
|
foreach ($arr as $row) {
|
|
$amazonOrder = empty($row['amazonorderid']) ? $row['orderid'] : $row['amazonorderid'];
|
|
$number = $row[$numberKey];
|
|
$qty = empty($row['quantity']) ? $row['quantitypurchased'] : $row['quantity'];
|
|
$taxRate = empty($row['mwst']) ? 0 : $row['taxrate'];
|
|
$row['taxrate'] = (float)$row['taxrate'];
|
|
$row['date'] = $row[$dateKey];
|
|
$row['quantity'] = $qty;
|
|
$row['bruttototal'] = $row['brutto_total'];
|
|
$row['nettototal'] = $row['netto_total'];
|
|
$row['preis'] = empty($row['mwst'])
|
|
? $row['itemprice_netto'] / $qty
|
|
: $row['itemprice'] / (1 + $row['taxrate'] / 100.0) / $qty;
|
|
$row['itemdiscount_price'][$taxRate] = empty($row['mwst'])
|
|
? $row['itempromotiondiscount_netto']
|
|
: $row['itempromotiondiscount'] / (1 + $row['taxrate'] / 100.0);
|
|
$row['shipping_net_price'][$taxRate] = empty($row['mwst'])
|
|
? $row['shippingprice_netto']
|
|
: $row['shippingprice'] / (1 + $row['taxrate'] / 100.0);
|
|
$row['shippingdiscount_price'][$taxRate] = empty($row['mwst'])
|
|
? $row['shippromotiondiscount_netto']
|
|
: $row['shippromotiondiscount'] / (1 + $row['taxrate'] / 100.0);
|
|
$row['giftwrap_price'] = empty($row['mwst'])
|
|
? $row['giftwrapprice_netto'] / $qty
|
|
: $row['giftwrapprice'] / (1 + $row['taxrate'] / 100.0) / $qty;
|
|
$row['giftwrapdiscount_price'] = empty($row['mwst'])
|
|
? $row['giftwrappromotiondiscount_netto']
|
|
: $row['giftwrappromotiondiscount'] / (1 + $row['taxrate'] / 100.0);
|
|
|
|
$row['giftwrap_price_with_discount'] = round(
|
|
(float)$row['giftwrapprice'] + (float)$row['giftwrappromotiondiscount'],
|
|
2
|
|
) / $qty;
|
|
$row['giftwrap_price_net_with_discount'] = empty($row['mwst'])
|
|
? round(
|
|
(float)$row['giftwrapprice_netto'] + (float)$row['giftwrappromotiondiscount_netto'],
|
|
2
|
|
) / $qty : round(
|
|
(float)$row['giftwrapprice'] + (float)$row['giftwrappromotiondiscount'],
|
|
2
|
|
) / $qty / (1.0 + $row['taxrate'] / 100.0);
|
|
|
|
$row['shipping_price_with_discount'][$taxRate] = round(
|
|
(float)$row['shippingprice'] + (float)$row['shippromotiondiscount'],
|
|
2
|
|
);
|
|
|
|
if (!isset($return[$type][$amazonOrder]['document'])) {
|
|
$return[$type][$amazonOrder]['document'] = $row;
|
|
} else {
|
|
$return[$type][$amazonOrder]['document']['brutto_total']
|
|
= round(
|
|
(float)$return[$type][$amazonOrder]['document']['brutto_total'] + (float)$row['brutto_total']
|
|
,
|
|
2
|
|
);
|
|
$return[$type][$amazonOrder]['document']['nettototal']
|
|
= round(
|
|
(float)$return[$type][$amazonOrder]['document']['nettototal'] + (float)$row['nettototal']
|
|
,
|
|
2
|
|
);
|
|
|
|
if (!isset($return[$type][$amazonOrder]['document']['shipping_net_price'][$taxRate])) {
|
|
$return[$type][$amazonOrder]['document']['shipping_net_price'][$taxRate] = 0.0;
|
|
}
|
|
$return[$type][$amazonOrder]['document']['shipping_net_price'][$taxRate]
|
|
= (float)$return[$type][$amazonOrder]['document']['shipping_net_price'][$taxRate]
|
|
+ (float)$row['shipping_net_price'][$taxRate];
|
|
|
|
if (!isset($return[$type][$amazonOrder]['document']['shippingdiscount_price'][$taxRate])) {
|
|
$return[$type][$amazonOrder]['document']['shippingdiscount_price'][$taxRate] = 0.0;
|
|
}
|
|
$return[$type][$amazonOrder]['document']['shippingdiscount_price'][$taxRate]
|
|
= (float)$return[$type][$amazonOrder]['document']['shippingdiscount_price'][$taxRate]
|
|
+ (float)$row['shippingdiscount_price'][$taxRate];
|
|
|
|
|
|
if (!isset($return[$type][$amazonOrder]['document']['shipping_price_with_discount'][$taxRate])) {
|
|
$return[$type][$amazonOrder]['document']['shipping_price_with_discount'][$taxRate] = 0.0;
|
|
}
|
|
|
|
$return[$type][$amazonOrder]['document']['shipping_price_with_discount'][$taxRate]
|
|
= (float)$return[$type][$amazonOrder]['document']['shipping_price_with_discount'][$taxRate]
|
|
+ (float)$row['shipping_price_with_discount'][$taxRate];
|
|
|
|
if (!isset($return[$type][$amazonOrder]['document']['itemdiscount_price'][$taxRate])) {
|
|
$return[$type][$amazonOrder]['document']['itemdiscount_price'][$taxRate] = 0.0;
|
|
}
|
|
|
|
$return[$type][$amazonOrder]['document']['itemdiscount_price'][$taxRate]
|
|
= (float)$return[$type][$amazonOrder]['document']['itemdiscount_price'][$taxRate]
|
|
+ (float)$row['itemdiscount_price'][$taxRate];
|
|
}
|
|
$return[$type][$amazonOrder]['document']['brutto']
|
|
= $return[$type][$amazonOrder]['document']['brutto_total'];
|
|
$return[$type][$amazonOrder]['positions'][$number][] = $row;
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPositionFromExportCsv($file): array
|
|
{
|
|
$handle = fopen($file, 'r');
|
|
if (empty($handle)) {
|
|
throw new InvalidArgumentException('could not open file ' . $file);
|
|
}
|
|
|
|
$header = fgetcsv($handle, 0, ';');
|
|
$headerToKey = array_flip($header);
|
|
$isReturnOrder = in_array('rem_gs_nr', $header);
|
|
|
|
$amazonOrderKey = isset($headerToKey['orderid']) ? $headerToKey['orderid'] : null;
|
|
if ($amazonOrderKey === null) {
|
|
$amazonOrderKey = isset($headerToKey['amazonorderid']) ? $headerToKey['amazonorderid'] : null;
|
|
}
|
|
$returnOrderKey = isset($headerToKey['rem_gs_nr']) ? $headerToKey['rem_gs_nr'] : null;
|
|
$returnOderDateKey = isset($headerToKey['rem_date']) ? $headerToKey['rem_date'] : null;
|
|
$invDateKey = isset($headerToKey['inv_date']) ? $headerToKey['inv_date'] : null;
|
|
$invoiceKey = isset($headerToKey['inv_rech_nr']) ? $headerToKey['inv_rech_nr'] : null;
|
|
$skuKey = isset($headerToKey['sku']) ? $headerToKey['sku'] : null;
|
|
$quantityKey = isset($headerToKey['quantity']) ? $headerToKey['quantity'] : null;
|
|
if ($quantityKey === null) {
|
|
$quantityKey = isset($headerToKey['quantitypurchased']) ? $headerToKey['quantitypurchased'] : null;
|
|
}
|
|
$currencyKey = isset($headerToKey['currency']) ? $headerToKey['currency'] : null;
|
|
$taxrateKey = isset($headerToKey['taxrate']) ? $headerToKey['taxrate'] : null;
|
|
$bruttoTotalKey = isset($headerToKey['brutto_total']) ? $headerToKey['brutto_total'] : null;
|
|
$nettoTotalKey = isset($headerToKey['netto_total']) ? $headerToKey['netto_total'] : null;
|
|
$mwstKey = isset($headerToKey['mwst']) ? $headerToKey['mwst'] : null;
|
|
$dateKey = $isReturnOrder ? $returnOderDateKey : $invDateKey;
|
|
$numberKey = $isReturnOrder ? $returnOrderKey : $invoiceKey;
|
|
|
|
$type = $isReturnOrder ? 'returnorder' : 'invoice';
|
|
$return = [
|
|
$type => [],
|
|
];
|
|
while ($row = fgetcsv($handle, 0, ';')) {
|
|
$amazonOrder = $row[$amazonOrderKey];
|
|
$date = $row[$dateKey];
|
|
$number = $row[$numberKey];
|
|
$sku = $row[$skuKey];
|
|
$quantity = $row[$quantityKey];
|
|
$mwst = $row[$mwstKey];
|
|
$bruttoTotal = $row[$bruttoTotalKey];
|
|
$nettoTotal = $row[$nettoTotalKey];
|
|
$taxRate = $row[$taxrateKey];
|
|
$currency = $row[$currencyKey];
|
|
if (empty($amazonOrder) || empty($number)) {
|
|
continue;
|
|
}
|
|
$return[$type][$amazonOrder][$number][] = [
|
|
'date' => $date,
|
|
'sku' => $sku,
|
|
'quantity' => $quantity,
|
|
'mwst' => $mwst,
|
|
'bruttototal' => $bruttoTotal,
|
|
'nettototal' => $nettoTotal,
|
|
'taxrate' => $taxRate,
|
|
'currency' => $currency,
|
|
];
|
|
}
|
|
|
|
fclose($handle);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function isCreateOrderActive()
|
|
{
|
|
return !empty($this->config['createorder']);
|
|
}
|
|
|
|
private function validateConfig(): void
|
|
{
|
|
if (!empty($this->config['firmkeyid']) || !empty($this->config['clientidentifier'])) {
|
|
foreach (['firmkeyid', 'clientidentifier',] as $name) {
|
|
if (!isset($this->config[$name])) {
|
|
throw new InvalidArgumentException(sprintf('Config field %s not found', $name));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
if (!empty($this->config['ftp'])) {
|
|
foreach (['host', 'user', 'pass', 'dir', 'port'] as $name) {
|
|
if (!isset($this->config[$name])) {
|
|
throw new InvalidArgumentException(sprintf('Config field %s not found', $name));
|
|
}
|
|
}
|
|
} else {
|
|
if (empty($this->config['dir'])) {
|
|
throw new InvalidArgumentException('Config dir not found');
|
|
}
|
|
}
|
|
}
|
|
|
|
private function loadConfig(): void
|
|
{
|
|
$this->config = $this->getConfig();
|
|
if (!$this->useFtp) {
|
|
$this->config['ftp'] = 0;
|
|
}
|
|
$this->validateConfig();
|
|
if (!empty($this->config['firmkeyid'])) {
|
|
return;
|
|
}
|
|
|
|
if (!empty($this->config['ftp'])) {
|
|
$host = $this->config['host'];
|
|
$user = $this->config['user'];
|
|
$pass = $this->config['pass'];
|
|
$dir = $this->config['dir'];
|
|
$port = $this->config['port'];
|
|
$ftpConfig = new FtpConfig($host, $user, $pass, $dir, $port);
|
|
$this->filesystem = $this->filesystemFactory->createFtp($ftpConfig);
|
|
} else {
|
|
$fileSystemConfig = [
|
|
'permissions' => [
|
|
'file' => [
|
|
'public' => 0664,
|
|
'private' => 0664,
|
|
],
|
|
'dir' => [
|
|
'public' => 0775,
|
|
'private' => 0775,
|
|
],
|
|
],
|
|
];
|
|
$this->filesystem = $this->filesystemFactory->createLocal($this->config['dir'], $fileSystemConfig);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $doctype
|
|
* @param int $doctypeId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function getAmazonShopIdFromDocument($doctype, $doctypeId): ?int
|
|
{
|
|
if ($doctype === 'rechnung') {
|
|
$invoiceId = $doctypeId;
|
|
} else {
|
|
$invoiceId = $this->db->fetchValue(
|
|
'SELECT `rechnungid` FROM `gutschrift` WHERE `id` = :id',
|
|
['id' => $doctypeId]
|
|
);
|
|
}
|
|
if (empty($invoiceId)) {
|
|
return null;
|
|
}
|
|
$orderId = $this->db->fetchValue(
|
|
'SELECT `auftragid` FROM `rechnung` WHERE `id` = :id',
|
|
['id' => $invoiceId]
|
|
);
|
|
if (empty($orderId)) {
|
|
return null;
|
|
}
|
|
$shopId = (int)$this->db->fetchValue(
|
|
'SELECT `shop` FROM `auftrag` WHERE `id` = :id',
|
|
['id' => $orderId]
|
|
);
|
|
if (empty($shopId)) {
|
|
return null;
|
|
}
|
|
|
|
$shopId = $this->db->fetchValue(
|
|
'SELECT `id` FROM `shopexport` WHERE `id` = :id AND `modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($shopId)) {
|
|
return null;
|
|
}
|
|
|
|
return (int)$shopId;
|
|
}
|
|
|
|
/**
|
|
* @param int $shopId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function getDiscountArticleIdByShopId($shopId): ?int
|
|
{
|
|
$discountArticle = $this->db->fetchRow(
|
|
'SELECT `art`.`id`
|
|
FROM `shopexport` AS `s`
|
|
LEFT JOIN `artikel` AS `art` ON `s`.`artikelrabatt` = art.id
|
|
AND (`art`.`geloescht` = 0 OR `art`.`geloescht` IS NULL)
|
|
AND (`art`.`intern_gesperrt` = 0 OR `art`.`intern_gesperrt` IS NULL)
|
|
WHERE `s`.`id` = :id AND `s`.`modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($discountArticle)) {
|
|
return null;
|
|
}
|
|
if ($discountArticle['id'] > 0) {
|
|
return (int)$discountArticle['id'];
|
|
}
|
|
|
|
return $this->createDiscountArticleByShopId($shopId);
|
|
}
|
|
|
|
/**
|
|
* @param int $shopId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function getShippingArticleIdByShopId($shopId): ?int
|
|
{
|
|
$shippingArticle = $this->db->fetchRow(
|
|
'SELECT `art`.`id`
|
|
FROM `shopexport` AS `s`
|
|
LEFT JOIN `artikel` AS `art` ON `s`.`artikelporto` = art.id
|
|
AND (`art`.`geloescht` = 0 OR `art`.`geloescht` IS NULL)
|
|
AND (`art`.`intern_gesperrt` = 0 OR `art`.`intern_gesperrt` IS NULL)
|
|
WHERE `s`.`id` = :id AND `s`.`modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($shippingArticle)) {
|
|
return null;
|
|
}
|
|
if ($shippingArticle['id'] > 0) {
|
|
return (int)$shippingArticle['id'];
|
|
}
|
|
|
|
return $this->createShippingArticleByShopId($shopId);
|
|
}
|
|
|
|
/**
|
|
* @param int $shopId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function getGiftWrapArticleIdByShopId($shopId): ?int
|
|
{
|
|
$json = $this->db->fetchValue(
|
|
'SELECT `einstellungen_json` FROM `shopexport` WHERE `id` = :id AND `modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($json)) {
|
|
return null;
|
|
}
|
|
|
|
$json = @json_decode($json, true);
|
|
if (empty($json) || empty($json['felder']) || empty($json['felder']['giftwrap'])) {
|
|
return null;
|
|
}
|
|
|
|
return (int)$json['felder']['giftwrap'];
|
|
}
|
|
|
|
/**
|
|
* @param int $shopId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function createDiscountArticleByShopId($shopId): ?int
|
|
{
|
|
$shop = $this->db->fetchRow(
|
|
'SELECT `s`.`projekt`, `art`.`id`
|
|
FROM `shopexport` AS `s`
|
|
LEFT JOIN `artikel` AS `art` ON `s`.`artikelrabatt` = art.id
|
|
AND (`art`.`geloescht` = 0 OR `art`.`geloescht` IS NULL)
|
|
AND (`art`.`intern_gesperrt` = 0 OR `art`.`intern_gesperrt` IS NULL)
|
|
WHERE `s`.`id` = :id AND `s`.`modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($shop) || !empty($shop['id'])) {
|
|
return null;
|
|
}
|
|
$discountArticle = [
|
|
'projekt' => $shop['projekt'],
|
|
'name_de' => 'Rabatt',
|
|
'name_en' => 'Discount',
|
|
'lagerartikel' => 0,
|
|
];
|
|
$discountArticle['nummer'] = $this->app->erp->GetNextArtikelnummer('', '1', $shop['projekt']);
|
|
$discountArticleId = (int)$this->app->erp->InsertUpdateArtikel($discountArticle);
|
|
if ($discountArticleId <= 0) {
|
|
return null;
|
|
}
|
|
$this->db->perform(
|
|
'UPDATE `shopexport` SET `artikelrabatt` = :articleId WHERE `id` = :shopId ',
|
|
[
|
|
'articleId' => $discountArticleId,
|
|
'shopId' => $shopId,
|
|
]
|
|
);
|
|
|
|
return $discountArticleId;
|
|
}
|
|
|
|
/**
|
|
* @param int $shopId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function createShippingArticleByShopId($shopId): ?int
|
|
{
|
|
$shop = $this->db->fetchRow(
|
|
'SELECT `s`.`projekt`, `art`.`id`
|
|
FROM `shopexport` AS `s`
|
|
LEFT JOIN `artikel` AS `art` ON `s`.`artikelporto` = art.id
|
|
AND (`art`.`geloescht` = 0 OR `art`.`geloescht` IS NULL)
|
|
AND (`art`.`intern_gesperrt` = 0 OR `art`.`intern_gesperrt` IS NULL)
|
|
WHERE `s`.`id` = :id AND `s`.`modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($shop) || !empty($shop['id'])) {
|
|
return null;
|
|
}
|
|
$firstShippingArticle = $this->db->fetchRow(
|
|
'SELECT `art`.`id`
|
|
FROM `artikel` AS `art`
|
|
LEFT JOIN `projekt` AS `p` ON `art`.projekt = p.id
|
|
WHERE `art`.`porto` = 1
|
|
AND (`art`.`geloescht` IS NOT NULL OR `art`.geloescht = 0)
|
|
AND (`art`.`intern_gesperrt` = 0 OR `art`.`intern_gesperrt` IS NULL)
|
|
AND (`p`.`id` IS NULL OR p.`oeffentlich` = 1)
|
|
'
|
|
);
|
|
if (!empty($firstShippingArticle)) {
|
|
$this->db->perform(
|
|
'UPDATE `shopexport` SET `artikelporto` = :articleId WHERE `id` = :shopId ',
|
|
[
|
|
'articleId' => (int)$firstShippingArticle['id'],
|
|
'shopId' => $shopId,
|
|
]
|
|
);
|
|
|
|
return (int)$firstShippingArticle['id'];
|
|
}
|
|
$shippingArticle = ['projekt' => $shop['projekt'], 'name_de' => 'Porto', 'proto' => 1];
|
|
$shippingArticle['nummer'] = $this->app->erp->GetNextArtikelnummer('', '1', $shop['projekt']);
|
|
$shippingArticleId = (int)$this->app->erp->InsertUpdateArtikel($shippingArticle);
|
|
if ($shippingArticleId <= 0) {
|
|
return null;
|
|
}
|
|
$this->db->perform(
|
|
'UPDATE `shopexport` SET `artikelporto` = :articleId WHERE `id` = :shopId ',
|
|
[
|
|
'articleId' => $shippingArticleId,
|
|
'shopId' => $shopId,
|
|
]
|
|
);
|
|
|
|
return $shippingArticleId;
|
|
}
|
|
|
|
/**
|
|
* @param int $shopId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function createGiftWrapArticle($shopId): ?int
|
|
{
|
|
$shop = $this->db->fetchRow(
|
|
'SELECT `projekt`, `einstellungen_json` FROM `shopexport` WHERE `id` = :id AND `modulename` = :module_name',
|
|
[
|
|
'id' => $shopId,
|
|
'module_name' => 'shopimporter_amazon',
|
|
]
|
|
);
|
|
if (empty($shop)) {
|
|
return null;
|
|
}
|
|
$giftwrapArticle = ['projekt' => $shop['projekt'], 'name_de' => 'Geschenkverpackung', 'lagerartikel' => 1];
|
|
$giftwrapArticle['nummer'] = $this->app->erp->GetNextArtikelnummer('', '1', $shop['projekt']);
|
|
$giftwrapArticleId = (int)$this->app->erp->InsertUpdateArtikel($giftwrapArticle);
|
|
if ($giftwrapArticleId <= 0) {
|
|
return null;
|
|
}
|
|
$json = @json_decode($shop['einstellungen_json'], true);
|
|
if (!is_array($json)) {
|
|
$json = ['felder' => []];
|
|
}
|
|
if (!isset($json['felder'])) {
|
|
$json['felder'] = [];
|
|
}
|
|
$json['felder']['giftwrap'] = $giftwrapArticleId;
|
|
$this->db->perform(
|
|
'UPDATE `shopexport` SET `einstellungen_json` = :json WHERE `id` = :id',
|
|
[
|
|
'json' => json_encode($json),
|
|
'id' => $shopId,
|
|
]
|
|
);
|
|
|
|
return $giftwrapArticleId;
|
|
}
|
|
|
|
/**
|
|
* @param string $document
|
|
* @param int $positionId
|
|
* @param float $tax
|
|
*/
|
|
private function changePositionTax($document, $positionId, $tax): void
|
|
{
|
|
if (!is_numeric($tax) || empty($positionId) || !in_array($document, ['rechnung', 'gutschrift'])) {
|
|
return;
|
|
}
|
|
|
|
if ($document === 'rechnung') {
|
|
$this->db->perform(
|
|
'UPDATE `rechnung_position` SET `steuersatz` = :tax WHERE `id` = :positionId',
|
|
[
|
|
'tax' => (float)$tax,
|
|
'positionId' => (int)$positionId,
|
|
]
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if ($document === 'gutschrift') {
|
|
$this->db->perform(
|
|
'UPDATE `gutschrift_position` SET `steuersatz` = :tax WHERE `id` = :positionId',
|
|
[
|
|
'tax' => (float)$tax,
|
|
'positionId' => (int)$positionId,
|
|
]
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $doctype
|
|
* @param int $doctypeId
|
|
* @param float|string $tax
|
|
* @param float $price
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function addDiscountPosition($doctype, $doctypeId, $tax, $price): ?int
|
|
{
|
|
$shopId = $this->getAmazonShopIdFromDocument($doctype, $doctypeId);
|
|
if ($shopId === null) {
|
|
return null;
|
|
}
|
|
$discountArticleId = $this->getDiscountArticleIdByShopId($shopId);
|
|
if ($discountArticleId === null) {
|
|
$discountArticleId = $this->createDiscountArticleByShopId($shopId);
|
|
if ($discountArticleId === null) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
$document = $this->getDocumentInfoForAddPosition($doctype, $doctypeId);
|
|
if ($document === null) {
|
|
return null;
|
|
}
|
|
$discountArticle = $this->getArticleInfoForAddPosition($document, $discountArticleId);
|
|
if ($discountArticle === null) {
|
|
return null;
|
|
}
|
|
|
|
$positionId = $this->app->erp->AddPositionManuellPreisNummer(
|
|
$doctype,
|
|
$doctypeId,
|
|
0,
|
|
$discountArticle['nummer'],
|
|
1,
|
|
$discountArticle['name'],
|
|
$price,
|
|
!empty($tax) && in_array($tax, ['normal', 'ermaessigt', 'befreit']) ? $tax : '',
|
|
0,
|
|
0,
|
|
$document['waehrung']
|
|
);
|
|
|
|
|
|
if (is_numeric($tax)) {
|
|
$this->changePositionTax($doctype, $positionId, $tax);
|
|
}
|
|
|
|
if (empty($positionId)) {
|
|
return null;
|
|
}
|
|
|
|
return (int)$positionId;
|
|
}
|
|
|
|
/**
|
|
* @param string $doctype
|
|
* @param int $doctypeId
|
|
* @param float|string $tax
|
|
* @param float $price
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function addShippingPosition($doctype, $doctypeId, $tax, $price): ?int
|
|
{
|
|
$shopId = $this->getAmazonShopIdFromDocument($doctype, $doctypeId);
|
|
if ($shopId === null) {
|
|
return null;
|
|
}
|
|
$shippingArticleId = $this->getShippingArticleIdByShopId($shopId);
|
|
if ($shippingArticleId === null) {
|
|
$shippingArticleId = $this->createShippingArticleByShopId($shopId);
|
|
if ($shippingArticleId === null) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
$document = $this->getDocumentInfoForAddPosition($doctype, $doctypeId);
|
|
if ($document === null) {
|
|
return null;
|
|
}
|
|
$shippingArticle = $this->getArticleInfoForAddPosition($document, $shippingArticleId);
|
|
if ($shippingArticle === null) {
|
|
return null;
|
|
}
|
|
|
|
$positionId = $this->app->erp->AddPositionManuellPreisNummer(
|
|
$doctype,
|
|
$doctypeId,
|
|
0,
|
|
$shippingArticle['nummer'],
|
|
1,
|
|
$shippingArticle['name'],
|
|
$price,
|
|
!empty($tax) && in_array($tax, ['normal', 'ermaessigt', 'befreit']) ? $tax : '',
|
|
0,
|
|
0,
|
|
$document['waehrung']
|
|
);
|
|
|
|
if (is_numeric($tax)) {
|
|
$this->changePositionTax($doctype, $positionId, $tax);
|
|
}
|
|
|
|
if (empty($positionId)) {
|
|
return null;
|
|
}
|
|
|
|
return (int)$positionId;
|
|
}
|
|
|
|
/**
|
|
* @param string $doctype
|
|
* @param int $doctypeId
|
|
*
|
|
* @return array|null
|
|
*/
|
|
private function getDocumentInfoForAddPosition($doctype, $doctypeId): ?array
|
|
{
|
|
if ($doctype === 'rechnung') {
|
|
$document = $this->db->fetchRow(
|
|
'SELECT `waehrung`, `sprache` FROM `rechnung` WHERE `id` = :id',
|
|
['id' => $doctypeId]
|
|
);
|
|
} elseif ($doctype === 'gutschrift') {
|
|
$document = $this->db->fetchRow(
|
|
'SELECT `waehrung`, `sprache` FROM `gutschrift` WHERE `id` = :id',
|
|
['id' => $doctypeId]
|
|
);
|
|
} else {
|
|
return null;
|
|
}
|
|
if (empty($document)) {
|
|
return null;
|
|
}
|
|
if (empty($document['waehrung'])) {
|
|
$document['waehrung'] = 'EUR';
|
|
}
|
|
|
|
return $document;
|
|
}
|
|
|
|
/**
|
|
* @param array $document
|
|
* @param int $articleId
|
|
*
|
|
* @return array|null
|
|
*/
|
|
private function getArticleInfoForAddPosition($document, $articleId): ?array
|
|
{
|
|
$article = $this->db->fetchRow(
|
|
'SELECT `nummer`, `name_de`, `name_en` FROM `artikel` WHERE `id` = :id ',
|
|
['id' => $articleId]
|
|
);
|
|
if (empty($article)) {
|
|
return null;
|
|
}
|
|
$name = $article['name_de'];
|
|
if (
|
|
!empty($article['name_en'])
|
|
&& !empty($document['sprache'])
|
|
&& !in_array($document['sprache'], ['deutsch', 'german', 'de', 'DE'])
|
|
) {
|
|
$name = $article['name_en'];
|
|
}
|
|
|
|
$article['name'] = $name;
|
|
|
|
return $article;
|
|
}
|
|
|
|
/**
|
|
* @param string $doctype
|
|
* @param int $doctypeId
|
|
* @param int $quantity
|
|
* @param float $price
|
|
* @param null|int $orderId
|
|
*
|
|
* @return int|null
|
|
*/
|
|
private function addGiftWrapPositon($doctype, $doctypeId, $quantity, $price, $orderId = null): ?int
|
|
{
|
|
if ($doctype !== 'rechnung') {
|
|
$createOrderPosition = false;
|
|
}
|
|
$shopId = $this->getAmazonShopIdFromDocument($doctype, $doctypeId);
|
|
if ($shopId === null) {
|
|
return null;
|
|
}
|
|
$giftWrapArticleId = $this->getGiftWrapArticleIdByShopId($shopId);
|
|
if ($giftWrapArticleId === null) {
|
|
$giftWrapArticleId = $this->createGiftWrapArticle($shopId);
|
|
if ($giftWrapArticleId === null) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
$document = $this->getDocumentInfoForAddPosition($doctype, $doctypeId);
|
|
if ($document === null) {
|
|
return null;
|
|
}
|
|
|
|
$giftWrapArticle = $this->getArticleInfoForAddPosition($document, $giftWrapArticleId);
|
|
if ($giftWrapArticle === null) {
|
|
return null;
|
|
}
|
|
|
|
$positionId = (int)$this->app->erp->AddPositionManuellPreisNummer(
|
|
$doctype,
|
|
$doctypeId,
|
|
0,
|
|
$giftWrapArticle['nummer'],
|
|
$quantity,
|
|
$giftWrapArticle['name'],
|
|
$price,
|
|
'',
|
|
0,
|
|
0,
|
|
$document['waehrung']
|
|
);
|
|
|
|
if (empty($positionId)) {
|
|
return null;
|
|
}
|
|
|
|
if ($createOrderPosition) {
|
|
$orderPositionId = (int)$this->app->erp->AddPositionManuellPreisNummer(
|
|
'auftrag',
|
|
$orderId,
|
|
0,
|
|
$giftWrapArticle['nummer'],
|
|
$quantity,
|
|
$giftWrapArticle['name'],
|
|
$price,
|
|
'',
|
|
0,
|
|
0,
|
|
$document['waehrung']
|
|
);
|
|
$this->db->perform(
|
|
'UPDATE `rechnung_position` SET `auftrag_position_id` = :orderPositionId WHERE `id` = :id',
|
|
[
|
|
'orderPositionId' => $orderPositionId,
|
|
'id' => $positionId,
|
|
]
|
|
);
|
|
}
|
|
|
|
return $positionId;
|
|
}
|
|
|
|
/**
|
|
* @param string $type
|
|
* @param int $documentId
|
|
* @param array $documentRows
|
|
* @param array $positions
|
|
* @param null|int $orderId
|
|
*/
|
|
private function addDiscountArticles($type, $documentId, $documentRows, $positions, $orderId = null): void
|
|
{
|
|
if (empty($documentId)
|
|
|| empty($documentRows)
|
|
|| empty($positions)
|
|
|| $documentId <= 0
|
|
|| !in_array($type, ['invoice', 'returnorder'])) {
|
|
return;
|
|
}
|
|
$doctype = $type === 'invoice' ? 'rechnung' : 'gutschrift';
|
|
foreach ($documentRows as $documentRow) {
|
|
if (empty($documentRow['itemdiscount_price'])) {
|
|
continue;
|
|
}
|
|
foreach ($documentRow['itemdiscount_price'] as $taxRate => $price) {
|
|
if ($price == 0) {
|
|
continue;
|
|
}
|
|
|
|
$positionId = (int)$this->addDiscountPosition($doctype, $documentId, $taxRate, $price);
|
|
if ($orderId !== null) {
|
|
$orderPositionId = (int)$this->addDiscountPosition('auftrag', $orderId, $taxRate, $price);
|
|
$this->db->perform(
|
|
'UPDATE `rechnung_position` SET `auftrag_position_id` = :orderPositionId WHERE `id` = :id',
|
|
[
|
|
'orderPositionId' => $orderPositionId,
|
|
'id' => $positionId,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $type
|
|
* @param int $documentId
|
|
* @param array $documentRows
|
|
* @param array $positions
|
|
* @param null|int $orderId
|
|
*/
|
|
private function addShippingArticles($type, $documentId, $documentRows, $positions, $orderId = null): void
|
|
{
|
|
if (empty($documentId)
|
|
|| empty($documentRows)
|
|
|| empty($positions)
|
|
|| $documentId <= 0
|
|
|| !in_array($type, ['invoice', 'returnorder'])) {
|
|
return;
|
|
}
|
|
$doctype = $type === 'invoice' ? 'rechnung' : 'gutschrift';
|
|
foreach ($documentRows as $documentRow) {
|
|
if (empty($documentRow['shipping_price_with_discount'])) {
|
|
continue;
|
|
}
|
|
foreach ($documentRow['shipping_price_with_discount'] as $taxRate => $price) {
|
|
if ($price == 0) {
|
|
continue;
|
|
}
|
|
|
|
$positionId = (int)$this->addShippingPosition(
|
|
$doctype,
|
|
$documentId,
|
|
$taxRate,
|
|
$price / (1 + $taxRate / 100)
|
|
);
|
|
if ($orderId !== null) {
|
|
$orderPositionId = (int)$this->addShippingPosition(
|
|
'auftrag',
|
|
$orderId,
|
|
$taxRate,
|
|
$price / (1 + $taxRate / 100)
|
|
);
|
|
$this->db->perform(
|
|
'UPDATE `rechnung_position` SET `auftrag_position_id` = :orderPositionId WHERE `id` = :id',
|
|
[
|
|
'orderPositionId' => $orderPositionId,
|
|
'id' => $positionId,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $sku
|
|
*
|
|
* @return int
|
|
*/
|
|
private function getShopIdFromExternalNumber(string $sku): int
|
|
{
|
|
return (int)$this->db->fetchValue(
|
|
"SELECT af.shopid
|
|
FROM `artikelnummer_fremdnummern` AS `af`
|
|
INNER JOIN `shopexport` AS `s` ON af.shopid = s.id AND s.aktiv = 1
|
|
AND s.modulename LIKE 'shopimporter_amazon%'
|
|
WHERE af.aktiv = 1 AND af.nummer = :nummer AND af.nummer <> ''
|
|
LIMIT 1",
|
|
['nummer' => trim($sku)]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $type
|
|
* @param int $documentId
|
|
* @param array $positions
|
|
* @param null|int $orderId
|
|
*/
|
|
private function addPositions($type, $documentId, $positions, $orderId = null): void
|
|
{
|
|
if ($type === 'invoice') {
|
|
$this->db->perform(
|
|
'DELETE FROM `rechnung_position` WHERE `rechnung` = :invoice',
|
|
['invoice' => $documentId]
|
|
);
|
|
foreach ($positions as $key => $position) {
|
|
if ($position['quantity'] == 0) {
|
|
$position['quantity'] = 1;
|
|
}
|
|
$dataWithExternalNumber = null;
|
|
$shopId = $this->getShopIdFromExternalNumber((string)$position['sku']);
|
|
if ($shopId > 0) {
|
|
$dataWithExternalNumber = ['fremdnummer' => trim($position['sku'])];
|
|
}
|
|
|
|
$positionId = (int)$this->app->erp->AddPositionManuellPreisNummer(
|
|
'rechnung',
|
|
$documentId,
|
|
0,
|
|
$position['sku'],
|
|
$position['quantity'],
|
|
!isset($position['name']) ? $position['productname'] : $position['name'],
|
|
$position['taxrate'] > 0
|
|
? $position['itemprice'] / $position['quantity'] / (1 + $position['taxrate'] / 100) :
|
|
$position['itemprice_netto'] / $position['quantity'],
|
|
'',
|
|
0,
|
|
$shopId,
|
|
$position['currency'],
|
|
$dataWithExternalNumber
|
|
);
|
|
$this->db->perform(
|
|
'UPDATE `rechnung_position`
|
|
SET `steuersatz` = :taxRate, preis = :price
|
|
WHERE `id` = :id',
|
|
[
|
|
'taxRate' => $position['taxrate'],
|
|
'price' => $position['taxrate'] > 0
|
|
? $position['itemprice'] / $position['quantity'] / (1 + $position['taxrate'] / 100) :
|
|
$position['itemprice_netto'] / $position['quantity'],
|
|
'id' => $positionId,
|
|
]
|
|
);
|
|
if ($orderId !== null) {
|
|
$orderPositionId = (int)$this->app->erp->AddPositionManuellPreisNummer(
|
|
'auftrag',
|
|
$orderId,
|
|
0,
|
|
$position['sku'],
|
|
$position['quantity'],
|
|
!isset($position['name']) ? $position['productname'] : $position['name'],
|
|
$position['taxrate'] > 0
|
|
? $position['itemprice'] / $position['quantity'] / (1 + $position['taxrate'] / 100) :
|
|
$position['itemprice_netto'] / $position['quantity'],
|
|
'',
|
|
0,
|
|
$shopId,
|
|
$position['currency'],
|
|
$dataWithExternalNumber
|
|
);
|
|
$this->db->perform(
|
|
'UPDATE `auftrag_position`
|
|
SET `steuersatz` = :taxRate, preis = :price
|
|
WHERE `id` = :id',
|
|
[
|
|
'taxRate' => $position['taxrate'],
|
|
'price' => $position['taxrate'] > 0
|
|
? $position['itemprice'] / $position['quantity'] / (1 + $position['taxrate'] / 100) :
|
|
$position['itemprice_netto'] / $position['quantity'],
|
|
'id' => $orderPositionId,
|
|
]
|
|
);
|
|
$this->db->perform(
|
|
'UPDATE `rechnung_position`
|
|
SET `auftrag_position_id` = :orderPositionId
|
|
WHERE `id` = :id',
|
|
[
|
|
'orderPositionId' => $orderPositionId,
|
|
'id' => $positionId,
|
|
]
|
|
);
|
|
}
|
|
if (!empty($position['id'])) {
|
|
$this->db->perform(
|
|
'UPDATE `amazoninvoice_position`
|
|
SET `doctype_id` = :doctype_id, `doctype` = :doctype, `position_id` = :position_id
|
|
WHERE `id` = :id',
|
|
[
|
|
'doctype_id' => (int)$documentId,
|
|
'doctype' => 'rechnung',
|
|
'position_id' => (int)$positionId,
|
|
'id' => (int)$position['id'],
|
|
]
|
|
);
|
|
}
|
|
if (
|
|
!empty($position['giftwrap_price_net_with_discount'])
|
|
&& $position['giftwrap_price_net_with_discount'] != 0.0
|
|
) {
|
|
$this->addGiftWrapPositon(
|
|
'rechnung',
|
|
(int)$documentId,
|
|
$position['quantity'],
|
|
$position['giftwrap_price_net_with_discount'],
|
|
$orderId
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
$this->db->perform(
|
|
'DELETE FROM `gutschrift_position` WHERE `gutschrift` = :returnorder',
|
|
['returnorder' => $documentId]
|
|
);
|
|
foreach ($positions as $key => $position) {
|
|
if ($position['quantity'] == 0) {
|
|
$position['quantity'] = 1;
|
|
}
|
|
$dataWithExternalNumber = null;
|
|
$shopId = $this->getShopIdFromExternalNumber((string)$position['sku']);
|
|
if ($shopId > 0) {
|
|
$dataWithExternalNumber = ['fremdnummer' => trim($position['sku'])];
|
|
}
|
|
$positionId = $this->app->erp->AddPositionManuellPreisNummer(
|
|
'gutschrift',
|
|
$documentId,
|
|
0,
|
|
$position['sku'],
|
|
$position['quantity'],
|
|
$position['name'],
|
|
$position['price'],
|
|
'',
|
|
0,
|
|
$shopId,
|
|
$position['currency'],
|
|
$dataWithExternalNumber
|
|
);
|
|
$this->db->perform(
|
|
'UPDATE `gutschrift_position`
|
|
SET `steuersatz` = :taxRate, preis = :price
|
|
WHERE `id` = :id',
|
|
[
|
|
'taxRate' => $position['taxrate'],
|
|
'price' => $position['taxrate'] > 0
|
|
? $position['bruttototal'] / $position['quantity'] / (1 + $position['taxrate'] / 100) :
|
|
$position['nettototal'] / $position['quantity'],
|
|
'id' => $positionId,
|
|
]
|
|
);
|
|
if (!empty($position['id'])) {
|
|
$this->db->perform(
|
|
'UPDATE `amazoninvoice_position`
|
|
SET `doctype_id` = :doctype_id, `doctype` = :doctype, `position_id` = :position_id
|
|
WHERE `id` = :id',
|
|
[
|
|
'doctype_id' => (int)$documentId,
|
|
'doctype' => 'gutschrift',
|
|
'position_id' => (int)$positionId,
|
|
'id' => (int)$position['id'],
|
|
]
|
|
);
|
|
}
|
|
if (
|
|
!empty($position['giftwrap_price_net_with_discount'])
|
|
&& $position['giftwrap_price_net_with_discount'] != 0.0
|
|
) {
|
|
$this->addGiftWrapPositon(
|
|
'gutschrift',
|
|
(int)$documentId,
|
|
$position['quantity'],
|
|
$position['giftwrap_price_net_with_discount']
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $type
|
|
* @param int $documentId
|
|
* @param string $file
|
|
*/
|
|
private function archiveDocument($type, $documentId, $file): void
|
|
{
|
|
if ($type === 'invoice') {
|
|
$Brief = new RechnungPDF($this->app);
|
|
$table = 'rechnung';
|
|
} else {
|
|
$Brief = new GutschriftPDF($this->app);
|
|
$table = 'gutschrift';
|
|
}
|
|
$file = $this->app->erp->GetTMP() . $file;
|
|
if (!is_file($file)) {
|
|
throw new InvalidArgumentException(sprintf('file %s not found', $file));
|
|
}
|
|
$list = $Brief->getArchivedFiles($documentId, $table);
|
|
if (!empty($list)) {
|
|
foreach ($list as $pdfArchive) {
|
|
if (empty($pdfArchive['schreibschutz'])) {
|
|
continue;
|
|
}
|
|
$dir = $this->app->Conf->WFuserdata . '/pdfarchiv/' . $this->app->Conf->WFdbname . '/' . $table;
|
|
$pdfFile = Briefpapier::getPDFfolder($dir, $documentId, $pdfArchive['dateiname']);
|
|
|
|
if (@rename($file, $pdfFile)) {
|
|
$this->db->perform(
|
|
'UPDATE `pdfarchiv` SET `checksum` = :checksum WHERE `id` = :id',
|
|
['checksum' => md5_file($pdfFile), 'id' => $pdfArchive['id']]
|
|
);
|
|
|
|
return;
|
|
}
|
|
throw new InvalidArgumentException(sprintf('could not write file %s', $pdfFile));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|