mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-11-15 12:37:14 +01:00
1323 lines
42 KiB
PHP
1323 lines
42 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Xentral\Modules\Voucher\Gateway;
|
||
|
|
||
|
use Xentral\Components\Database\Database;
|
||
|
use Xentral\Modules\Voucher\Exception\InvalidArgumentException;
|
||
|
use Xentral\Modules\Voucher\Exception\RuntimeException;
|
||
|
use DateInterval;
|
||
|
use DateTime;
|
||
|
use Exception;
|
||
|
use ApplicationCore;
|
||
|
|
||
|
final class VoucherGateway
|
||
|
{
|
||
|
/** @var Database $db */
|
||
|
private $db;
|
||
|
|
||
|
/** @var ApplicationCore $app */
|
||
|
private $app;
|
||
|
|
||
|
/** @var array $validtypes */
|
||
|
private $validtypes;
|
||
|
|
||
|
/** @var array $digits */
|
||
|
private $digits;
|
||
|
|
||
|
/** @var array alphas */
|
||
|
private $alphas;
|
||
|
|
||
|
/**
|
||
|
* @param Database $database
|
||
|
* @param ApplicationCore $app
|
||
|
*/
|
||
|
public function __construct(Database $database, ApplicationCore $app)
|
||
|
{
|
||
|
$this->db = $database;
|
||
|
$this->app = $app;
|
||
|
$this->validtypes = [
|
||
|
'' => 'unbegrenzt',
|
||
|
'ThisYear' => 'Aktuelles Jahr',
|
||
|
'ThisYearPlus1' => 'Aktuelles Jahr + 1',
|
||
|
'ThisYearPlus2' => 'Aktuelles Jahr + 2',
|
||
|
'ThisYearPlus3' => 'Aktuelles Jahr + 3',
|
||
|
'Months3' => '3 Monate',
|
||
|
'Months6' => '6 Monate',
|
||
|
'Year1' => '1 Jahr',
|
||
|
'Year2' => '2 Jahre',
|
||
|
'Year3' => '3 Jahre',
|
||
|
];
|
||
|
for ($i = 0; $i < 10; $i++) {
|
||
|
$this->digits[] = (String)$i;
|
||
|
}
|
||
|
$a = ord('A');
|
||
|
for ($i = 0; $i < 26; $i++) {
|
||
|
$chr = chr($a + $i);
|
||
|
$this->alphas[] = $chr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
* @param float $amount
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function changeVoucherAmount($voucherId, $amount)
|
||
|
{
|
||
|
$voucher = $this->getById($voucherId);
|
||
|
if (empty($voucher)) {
|
||
|
return false;
|
||
|
}
|
||
|
$possibleToChange = $this->db->fetchCol(
|
||
|
sprintf(
|
||
|
'SELECT v.id FROM voucher AS v
|
||
|
LEFT JOIN rechnung AS re ON v.invoice_id = re.id
|
||
|
WHERE v.id = %d AND (v.invoice_id = 0 OR re.status <> \'versendet\')',
|
||
|
$voucherId
|
||
|
)
|
||
|
) > 0;
|
||
|
if (!$possibleToChange) {
|
||
|
return false;
|
||
|
}
|
||
|
$this->db->perform(
|
||
|
'UPDATE voucher
|
||
|
SET voucher_residual_value = :amount, voucher_original_value = :amount
|
||
|
WHERE id = :id ',
|
||
|
['amount' => $amount, 'id' => $voucherId]
|
||
|
);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $voucherId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getById($voucherId)
|
||
|
{
|
||
|
$sql = 'SELECT v.*
|
||
|
FROM voucher AS v
|
||
|
WHERE v.id = :voucher_id
|
||
|
LIMIT 1';
|
||
|
$result = $this->db->fetchRow($sql, [
|
||
|
'voucher_id' => $voucherId,
|
||
|
]);
|
||
|
if (empty($result)) {
|
||
|
throw new RuntimeException(sprintf('%s Vaucher not found.', $voucherId));
|
||
|
}
|
||
|
if ($result['tax_name'] !== 'ermaessigt' && $result['tax_name'] !== 'normal') {
|
||
|
$result['tax_name'] = 'befreit';
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $voucherCode
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getVoucherByCode($voucherCode)
|
||
|
{
|
||
|
$sql = 'SELECT v.*
|
||
|
FROM voucher AS v
|
||
|
WHERE v.voucher_code = :voucher_code';
|
||
|
|
||
|
|
||
|
$vouchers = $this->db->fetchAll($sql, [
|
||
|
'voucher_code' => $voucherCode,
|
||
|
]);
|
||
|
if (!empty($vouchers)) {
|
||
|
foreach ($vouchers as $key => $voucher) {
|
||
|
if ($voucher['tax_name'] !== 'normal' && $voucher['tax_name'] !== 'ermaessigt') {
|
||
|
$vouchers[$key]['tax_name'] = 'befreit';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $vouchers;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param string $voucherCode
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function isValidVoucher($voucherCode)
|
||
|
{
|
||
|
if (empty($voucherCode)) {
|
||
|
return false;
|
||
|
}
|
||
|
$sql = 'SELECT v.id
|
||
|
FROM voucher AS v
|
||
|
LEFT JOIN rechnung AS re ON v.invoice_id = re.id
|
||
|
WHERE v.voucher_code = :voucher_code
|
||
|
AND (IFNULL(valid_from,\'0000-00-00\') = \'0000-00-00\' OR IFNULL(valid_from,\'0000-00-00\') <= CURDATE())
|
||
|
AND (IFNULL(valid_to,\'0000-00-00\') = \'0000-00-00\' OR IFNULL(valid_to,\'0000-00-00\') >= CURDATE())
|
||
|
AND (v.invoice_id = 0 OR re.status = \'versendet\' OR re.status = \'freigegeben\')
|
||
|
LIMIT 1';
|
||
|
$result = $this->db->fetchAll($sql, [
|
||
|
'voucher_code' => $voucherCode,
|
||
|
]);
|
||
|
|
||
|
return !empty($result);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param array|int $voucher
|
||
|
* @param array $positions
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function isPossibleToUseVoucher($voucher, $positions)
|
||
|
{
|
||
|
if (empty($voucher)) {
|
||
|
return false;
|
||
|
}
|
||
|
if (is_int($voucher)) {
|
||
|
$voucher = $this->getById($voucher);
|
||
|
}
|
||
|
if (!$this->isValidVoucher($voucher['voucher_code'])) {
|
||
|
return false;
|
||
|
}
|
||
|
if (empty($positions) || !is_array($positions)) {
|
||
|
return true;
|
||
|
}
|
||
|
$taxName = !empty($voucher['tax_name']) ? $voucher['tax_name'] : 'normal';
|
||
|
if ($taxName === 'befreit') {
|
||
|
return true;
|
||
|
}
|
||
|
$return = false;
|
||
|
foreach ($positions as $position) {
|
||
|
if ((int)$position['id'] === (int)$voucher['article_id']) {
|
||
|
return false;
|
||
|
}
|
||
|
if ($taxName === !empty($position['umsatzsteuer']) ? $position['umsatzsteuer'] : 'normal') {
|
||
|
$return = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @refactor Order-Module
|
||
|
*
|
||
|
* @param int $docId
|
||
|
* @param string $doctype
|
||
|
*
|
||
|
* @return array Order
|
||
|
*/
|
||
|
public function getDocumentById($docId, $doctype = 'auftrag')
|
||
|
{
|
||
|
if ($doctype === 'rechnung') {
|
||
|
$sql = 'SELECT inv.*
|
||
|
FROM `rechnung` AS inv
|
||
|
WHERE inv.id = :id
|
||
|
LIMIT 1';
|
||
|
} else {
|
||
|
$sql = 'SELECT o.*
|
||
|
FROM auftrag AS o
|
||
|
WHERE o.id = :id
|
||
|
LIMIT 1';
|
||
|
}
|
||
|
$result = $this->db->fetchRow($sql, [
|
||
|
'id' => $docId,
|
||
|
]);
|
||
|
if (empty($result)) {
|
||
|
throw new InvalidArgumentException(
|
||
|
sprintf(
|
||
|
'%s %s does not exists.',
|
||
|
$doctype === 'rechnung' ? 'Invoice' : 'Order', $docId
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $orderId
|
||
|
* @param int $voucherId
|
||
|
*
|
||
|
* @return int OrderPositionId
|
||
|
*/
|
||
|
public function getVoucherPositionIdFromOrder($orderId, $voucherId)
|
||
|
{
|
||
|
$voucher = $this->getById($voucherId);
|
||
|
$articleId = $voucher['article_id'];
|
||
|
$sql = 'SELECT ap.id
|
||
|
FROM auftrag_position AS ap
|
||
|
WHERE ap.auftrag = :auftrag AND ap.artikel = :article_id LIMIT 1';
|
||
|
$result = $this->db->fetchValue($sql, [
|
||
|
'auftrag' => $orderId,
|
||
|
'article_id' => $articleId,
|
||
|
]);
|
||
|
if (empty($result)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'OrderPosition From Order %s not found.', $orderId
|
||
|
));
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherOrderId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getVoucherOrderById($voucherOrderId)
|
||
|
{
|
||
|
$sql = 'SELECT vo.*
|
||
|
FROM voucher_order AS vo
|
||
|
WHERE vo.id = :id
|
||
|
LIMIT 1';
|
||
|
$result = $this->db->fetchRow($sql, [
|
||
|
'id' => $voucherOrderId,
|
||
|
]);
|
||
|
if (empty($result)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'VocherOrder %s does not exists.', $voucherOrderId
|
||
|
));
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $doctypeId
|
||
|
* @param string $doctype
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getVoucherOrderByOrderId($doctypeId, $doctype = 'auftrag', $doctypePositionId = 0)
|
||
|
{
|
||
|
if($doctypePositionId > 0){
|
||
|
$sql = 'SELECT vo.*
|
||
|
FROM voucher_order AS vo
|
||
|
WHERE vo.order_id = :order_id AND vo.doctype = :doctype AND vo.order_position_id = :order_position_id
|
||
|
LIMIT 1';
|
||
|
$result = $this->db->fetchRow($sql, [
|
||
|
'order_id' => $doctypeId,
|
||
|
'doctype' => $doctype,
|
||
|
'order_position_id' => $doctypePositionId
|
||
|
]);
|
||
|
}else{
|
||
|
$sql = 'SELECT vo.*
|
||
|
FROM voucher_order AS vo
|
||
|
WHERE vo.order_id = :order_id AND vo.doctype = :doctype
|
||
|
LIMIT 1';
|
||
|
$result = $this->db->fetchRow($sql, [
|
||
|
'order_id' => $doctypeId,
|
||
|
'doctype' => $doctype,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (empty($result)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'VocherOrder %s does not exists.', $doctypeId
|
||
|
));
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
*
|
||
|
* @return float|null
|
||
|
*/
|
||
|
public function getResidualValueFromVoucherId($voucherId)
|
||
|
{
|
||
|
$sql = 'SELECT v.voucher_original_value - IFNULL(SUM(ABS(vo.voucher_value)),0)
|
||
|
FROM voucher AS v
|
||
|
LEFT JOIN voucher_order AS vo ON v.id = vo.voucher_id
|
||
|
WHERE v.id = :id
|
||
|
';
|
||
|
|
||
|
return $this->db->fetchValue($sql, ['id' => $voucherId]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $invoiceId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getInvoiceById($invoiceId)
|
||
|
{
|
||
|
$sql = 'SELECT inv.*
|
||
|
FROM rechnung AS inv
|
||
|
WHERE inv.id = :id
|
||
|
LIMIT 1';
|
||
|
$result = $this->db->fetchRow($sql, [
|
||
|
'id' => $invoiceId,
|
||
|
]);
|
||
|
if (empty($result)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'Inovice %s does not exists.', $invoiceId
|
||
|
));
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
* @param int $limit
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getVoucherOrdersFromVoucher($voucherId, $limit = 500)
|
||
|
{
|
||
|
$sql = 'SELECT vo.*
|
||
|
FROM voucher_order AS vo
|
||
|
WHERE vo.voucher_id = :id
|
||
|
LIMIT :limit';
|
||
|
|
||
|
return $this->db->fetchRow($sql, [
|
||
|
'id' => (int)$voucherId,
|
||
|
'limit' => (int)$limit,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int|array $voucher
|
||
|
* @param array $positions
|
||
|
*
|
||
|
* @return float|int|mixed
|
||
|
*/
|
||
|
public function getUsableVoucherValueByPos($voucher, $positions)
|
||
|
{
|
||
|
if (empty($voucher)) {
|
||
|
throw new RuntimeException('No Voucher given');
|
||
|
}
|
||
|
if (is_int($voucher)) {
|
||
|
$voucher = $this->getById($voucher);
|
||
|
}
|
||
|
if (!$this->isValidVoucher($voucher['voucher_code'])) {
|
||
|
throw new RuntimeException(sprintf('Voucher %s is not valid', $voucher['voucher_code']));
|
||
|
}
|
||
|
if (empty($voucher)) {
|
||
|
throw new RuntimeException('Voucher not found');
|
||
|
}
|
||
|
if (empty($positions) || !is_array($positions)) {
|
||
|
return 0;
|
||
|
}
|
||
|
if ($voucher['tax_name'] !== 'normal' && $voucher['tax_name'] !== 'ermaessigt') {
|
||
|
$voucher['tax_name'] = 'befreit';
|
||
|
}
|
||
|
$return = 0;
|
||
|
$taxName = !empty($voucher['tax_name']) ? $voucher['tax_name'] : 'befreit';
|
||
|
foreach ($positions as $position) {
|
||
|
if ($taxName === 'befreit' || $taxName === '' || $taxName === (!empty($position['umsatzsteuer']) ? $position['umsatzsteuer'] : 'normal')) {
|
||
|
$return += (float)(!empty($position['preis_brutto']) ? $position['preis_brutto'] : $position['preis']) * $position['menge'] * (1 - (!empty($position['rabatt']) ? $position['rabatt'] : 0) / 100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $return > $voucher['voucher_residual_value'] ? $voucher['voucher_residual_value'] : $return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param array $positions
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getVoucherTaxByPosPositions($positions)
|
||
|
{
|
||
|
$tax = '';
|
||
|
if (!empty($positions)) {
|
||
|
foreach ($positions as $position) {
|
||
|
if ($position['preis_netto'] <= 0) {
|
||
|
continue;
|
||
|
}
|
||
|
if ($tax === '') {
|
||
|
$tax = round($position['tax'], 2);
|
||
|
} elseif ($tax !== round($position['tax'], 2)) {
|
||
|
return 'befreit';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return empty($tax) ? 'befreit' : $tax;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int|array $voucherId
|
||
|
* @param int $doctypeId
|
||
|
* @param string $doctype
|
||
|
* @param float $voucher_value
|
||
|
* @param int $positionId
|
||
|
*
|
||
|
* @return int voucher_order_id
|
||
|
*/
|
||
|
public function addVoucherToOrder($voucherId, $doctypeId, $doctype, $voucher_value, $positionId = 0)
|
||
|
{
|
||
|
if (is_array($voucherId)) {
|
||
|
$voucher = $voucherId;
|
||
|
$voucherId = $voucher['id'];
|
||
|
}
|
||
|
|
||
|
if ($doctype !== 'rechnung') {
|
||
|
$doctype = 'auftrag';
|
||
|
}
|
||
|
|
||
|
if (!empty($positionId)) {
|
||
|
if ($doctype === 'auftrag') {
|
||
|
$positionId = (int)$this->db->fetchValue(
|
||
|
'SELECT id
|
||
|
FROM `auftrag_position`
|
||
|
WHERE id = :position_id AND `auftrag` = :doctype_id
|
||
|
LIMIT 1',
|
||
|
['position_id' => $positionId, 'doctype_id' => $doctypeId]
|
||
|
);
|
||
|
} else {
|
||
|
$positionId = (int)$this->db->fetchValue(
|
||
|
'SELECT id
|
||
|
FROM `rechnung_position`
|
||
|
WHERE id = :position_id AND `rechnung` = :doctype_id
|
||
|
LIMIT 1',
|
||
|
['position_id' => $positionId, 'doctype_id' => $doctypeId]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((float)$voucher_value === 0.0) {
|
||
|
throw new InvalidArgumentException('Voucher Value must not be 0.');
|
||
|
}
|
||
|
|
||
|
if ($doctypeId <= 0) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid %s.', $doctypeId, ($doctype === 'auftrag' ? 'OrderId' : 'InvoiceId')
|
||
|
));
|
||
|
}
|
||
|
if ($voucherId <= 0) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid VoucherId.', $voucherId
|
||
|
));
|
||
|
}
|
||
|
if (!is_numeric($voucher_value)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid Voucher Value.', $voucher_value
|
||
|
));
|
||
|
}
|
||
|
|
||
|
$document = $this->getDocumentById($doctypeId, $doctype);
|
||
|
|
||
|
if (empty($document)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid %s.', $doctypeId, ($doctype === 'auftrag' ? 'Order' : 'Invoice')
|
||
|
));
|
||
|
}
|
||
|
if (empty($voucher)) {
|
||
|
$voucher = $this->getById($voucherId);
|
||
|
}
|
||
|
if ($voucher['voucher_residual_value'] < $voucher_value) {
|
||
|
throw new RuntimeException('Voucher could not be added to order.');
|
||
|
}
|
||
|
|
||
|
if ($voucher['only_for_customer'] && (int)$voucher['address_id'] !== (int)$document['adresse']) {
|
||
|
throw new RuntimeException('Voucher-Address does not match to Order.');
|
||
|
}
|
||
|
|
||
|
if ($voucher['tax_name'] !== 'normal' && $voucher['tax_name'] !== 'ermaessigt') {
|
||
|
$voucher['tax_name'] = 'befreit';
|
||
|
}
|
||
|
|
||
|
/** @deprecated-block-start */
|
||
|
$voucher_value_net = -abs($voucher_value);
|
||
|
if ($voucher['tax_name'] === 'ermaessigt') {
|
||
|
$voucher_value_net /= $this->app->erp->GetSteuersatzErmaessigt(true, $doctypeId, $doctype);
|
||
|
} elseif ($voucher['tax_name'] !== 'befreit') {
|
||
|
$voucher_value_net /= $this->app->erp->GetSteuersatzNormal(true, $doctypeId, $doctype);
|
||
|
}
|
||
|
$article_name = $this->db->fetchValue(
|
||
|
'SELECT art.name_de FROM artikel AS art WHERE id = :article_id',
|
||
|
['article_id' => $voucher['article_id']]
|
||
|
);
|
||
|
$isPosEmpty = empty($positionId);
|
||
|
if ($doctype === 'rechnung') {
|
||
|
if ($isPosEmpty) {
|
||
|
$positionId = $this->app->erp->AddRechnungPositionManuell($doctypeId, $voucher['article_id'],
|
||
|
$voucher_value_net, 1,
|
||
|
$article_name, $voucher['voucher_code'], $voucher['currency']);
|
||
|
} else {
|
||
|
$this->db->perform('UPDATE `rechnung_position` SET preis = :price WHERE id = :position_id',
|
||
|
['price' => $voucher_value_net, 'position_id' => $positionId]
|
||
|
);
|
||
|
}
|
||
|
} elseif ($isPosEmpty) {
|
||
|
$positionId = (int)$this->app->erp->AddAuftragPositionManuell($doctypeId, $voucher['article_id'],
|
||
|
$voucher_value_net, 1,
|
||
|
$article_name, $voucher['voucher_code'], $voucher['currency']);
|
||
|
} else {
|
||
|
$this->db->perform('UPDATE `auftrag_position` SET preis = :price WHERE id = :position_id',
|
||
|
['price' => $voucher_value_net, 'position_id' => $positionId]
|
||
|
);
|
||
|
}
|
||
|
if (in_array($voucher['tax_name'], ['befreit', 'ermaessigt', 'normal'])) {
|
||
|
if ($doctype === 'auftrag') {
|
||
|
$this->db->perform('UPDATE `auftrag_position` SET umsatzsteuer = :tax_name WHERE id = :id',
|
||
|
['id' => (int)$positionId, 'tax_name' => $voucher['tax_name']]
|
||
|
);
|
||
|
} else {
|
||
|
$this->db->perform('UPDATE `rechnung_position` SET umsatzsteuer = :tax_name WHERE id = :id',
|
||
|
['id' => (int)$positionId, 'tax_name' => $voucher['tax_name']]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
/** @deprecated-block-end */
|
||
|
if (empty($positionId)) {
|
||
|
throw new RuntimeException('Voucher could not be added to order.');
|
||
|
}
|
||
|
|
||
|
$this->db->perform(
|
||
|
'UPDATE voucher SET voucher_residual_value = voucher_residual_value - :voucher_residual_value WHERE id = :id',
|
||
|
['id' => (int)$voucherId, 'voucher_residual_value' => $voucher_value]
|
||
|
);
|
||
|
|
||
|
$this->db->perform(
|
||
|
'INSERT INTO voucher_order (voucher_id, order_id, voucher_value, doctype, order_position_id)
|
||
|
VALUES (:voucher_id, :order_id, :order_value, :doctype, :order_position_id)',
|
||
|
[
|
||
|
'voucher_id' => (int)$voucherId,
|
||
|
'order_id' => (int)$doctypeId,
|
||
|
'order_position_id' => (int)$positionId,
|
||
|
'order_value' => abs((float)$voucher_value),
|
||
|
'doctype' => $doctype
|
||
|
]
|
||
|
);
|
||
|
$insertId = (int)$this->db->lastInsertId();
|
||
|
if ($insertId === 0) {
|
||
|
if ($doctype === 'rechnung') {
|
||
|
$this->db->perform('DELETE FROM rechnung_position WHERE id = :id', ['id' => $positionId]);
|
||
|
throw new RuntimeException('Voucher could not be added to invoice.');
|
||
|
}
|
||
|
$this->db->perform('DELETE FROM auftrag_position WHERE id = :id', ['id' => $positionId]);
|
||
|
throw new RuntimeException('Voucher could not be added to order.');
|
||
|
}
|
||
|
$this->recalculateResidualValue($voucherId);
|
||
|
$this->changeAddress($voucherId, $document['adresse']);
|
||
|
|
||
|
return $insertId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
* @param int $adressId
|
||
|
*/
|
||
|
private function changeAddress($voucherId, $adressId)
|
||
|
{
|
||
|
$voucher = $this->getById($voucherId);
|
||
|
if (empty($voucher['address_id']) || $voucher['address_id'] !== $adressId) {
|
||
|
$this->db->perform(
|
||
|
'UPDATE voucher SET address_id = :address_id WHERE id = :id ',
|
||
|
['address_id' => $adressId, 'id' => $voucherId]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
* @param string $doctype
|
||
|
* @param int $doctypeId
|
||
|
* @param int $positionId
|
||
|
* @param int $reedemed
|
||
|
* @param float $redeemedValue
|
||
|
* @param int $projectId
|
||
|
* @param string $username
|
||
|
*/
|
||
|
public function addVoucherPosLog(
|
||
|
$voucherId,
|
||
|
$doctype,
|
||
|
$doctypeId,
|
||
|
$positionId,
|
||
|
$reedemed,
|
||
|
$redeemedValue,
|
||
|
$projectId = 0,
|
||
|
$username = ''
|
||
|
) {
|
||
|
if ((float)$redeemedValue === 0.0) {
|
||
|
throw new InvalidArgumentException('Redeemed Value must not be 0.');
|
||
|
}
|
||
|
|
||
|
if ($doctypeId <= 0) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid %s.', $doctypeId, ($doctype === 'auftrag' ? 'OrderId' : 'InvoiceId')
|
||
|
));
|
||
|
}
|
||
|
if ($voucherId <= 0) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid VoucherId.', $voucherId
|
||
|
));
|
||
|
}
|
||
|
if (!is_numeric($redeemedValue)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'%s is not a valid Voucher Value.', $redeemedValue
|
||
|
));
|
||
|
}
|
||
|
|
||
|
$this->getById($voucherId);
|
||
|
|
||
|
$this->db->perform('INSERT INTO voucher_pos
|
||
|
(voucher_id, project_id, redeemed, redeemed_value, doctype, doctype_id, position_id, created_by) VALUES
|
||
|
(:voucher_id, :project_id, :redeemed,:reedemed_value, :doctype,:doctype_id, :position_id, :created_by)',
|
||
|
[
|
||
|
'voucher_id' => (int)$voucherId,
|
||
|
'project_id' => (int)$projectId,
|
||
|
'redeemed' => (int)$reedemed,
|
||
|
'reedemed_value' => abs((float)$redeemedValue),
|
||
|
'doctype' => (String)$doctype,
|
||
|
'doctype_id' => (int)$doctypeId,
|
||
|
'position_id' => (int)$positionId,
|
||
|
'created_by' => (String)$username,
|
||
|
]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $voucherOrderId
|
||
|
* @param bool $with_position
|
||
|
*
|
||
|
* @return bool true if successful
|
||
|
*/
|
||
|
public function deleteVoucherFromOrder($voucherOrderId, $with_position = true)
|
||
|
{
|
||
|
try {
|
||
|
$voucherOrder = $this->getVoucherOrderById($voucherOrderId);
|
||
|
$orderPositionId = $this->getVoucherPositionIdFromOrder($voucherOrder['order_id'],
|
||
|
$voucherOrder['voucher_id']);
|
||
|
if (!$orderPositionId) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ($with_position) {
|
||
|
/** @deprecated-block-start */
|
||
|
$doctype = $voucherOrder['doctype'] === 'rechnung' ? 'rechnung' : 'auftrag';
|
||
|
$doctypePosition = $doctype . '_position';
|
||
|
$this->app->YUI->SortListEvent('del', $doctypePosition, $doctype, $voucherOrder['order_id'],
|
||
|
$orderPositionId);
|
||
|
/** @deprecated-block-end */
|
||
|
}
|
||
|
|
||
|
$affectedRows = $this->db->fetchAffected(
|
||
|
'UPDATE voucher SET voucher_residual_value = voucher_residual_value - :voucher_residual_value WHERE id = :id',
|
||
|
['id' => (int)$voucherOrder['voucher_id'], 'voucher_residual_value' => $voucherOrder['voucher_value']]
|
||
|
);
|
||
|
if ($affectedRows === 1) {
|
||
|
$this->db->perform('DELETE FROM voucher_order WHERE id = :id', ['id' => $voucherOrder['id']]);
|
||
|
$this->recalculateResidualValue($voucherOrder['voucher_id']);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} catch (Exception $e) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $code
|
||
|
* @param int $articleId
|
||
|
* @param float $voucherValue
|
||
|
* @param int $invoiceId
|
||
|
* @param int $invoicePositionId
|
||
|
* @param string $taxName
|
||
|
* @param string $currency
|
||
|
* @param string|null $validFrom
|
||
|
* @param string|null $validTo
|
||
|
* @param bool $showCodeOnDocument
|
||
|
* @param bool $onlyForCustomer
|
||
|
* @param int $addressId
|
||
|
*
|
||
|
* @return int voucher_id
|
||
|
*/
|
||
|
public function create(
|
||
|
$code,
|
||
|
$articleId,
|
||
|
$voucherValue,
|
||
|
$invoiceId,
|
||
|
$invoicePositionId,
|
||
|
$taxName,
|
||
|
$currency = 'EUR',
|
||
|
$validFrom = null,
|
||
|
$validTo = null,
|
||
|
$showCodeOnDocument = true,
|
||
|
$onlyForCustomer = false,
|
||
|
$addressId = 0
|
||
|
) {
|
||
|
try {
|
||
|
$voucher = $this->getVoucherByCode($code);
|
||
|
if (!empty($voucher)) {
|
||
|
throw new RuntimeException('Voucher with code allready exists');
|
||
|
}
|
||
|
|
||
|
if ($taxName !== 'normal' && $taxName !== 'ermaessigt') {
|
||
|
$taxName = 'befreit';
|
||
|
}
|
||
|
|
||
|
$this->db->perform('INSERT INTO voucher
|
||
|
(voucher_date, article_id, voucher_code, voucher_original_value,voucher_residual_value,
|
||
|
valid_from,valid_to, invoice_id, invoice_position_id, tax_name,currency,show_code_on_document, only_for_customer,address_id)
|
||
|
VALUES (now(), :article_id ,:voucher_code, :voucher_value, :voucher_value,
|
||
|
:valid_from, :valid_to, :invoice_id, :invoice_position_id , :tax_name, :currency, :show_code_on_document,:only_for_customer,:address_id)',
|
||
|
[
|
||
|
'article_id' => $articleId,
|
||
|
'voucher_code' => $code,
|
||
|
'voucher_value' => (float)$voucherValue,
|
||
|
'valid_from' => $validFrom,
|
||
|
'valid_to' => $validTo,
|
||
|
'invoice_id' => $invoiceId,
|
||
|
'invoice_position_id' => $invoicePositionId,
|
||
|
'tax_name' => (String)$taxName,
|
||
|
'currency' => !empty($currency) ? $currency : 'EUR',
|
||
|
'show_code_on_document' => $showCodeOnDocument ? 1 : 0,
|
||
|
'only_for_customer' => $onlyForCustomer ? 1 : 0,
|
||
|
'address_id' => (int)$addressId,
|
||
|
]
|
||
|
);
|
||
|
|
||
|
return (int)$this->db->lastInsertId();
|
||
|
} catch (Exception $e) {
|
||
|
throw new RuntimeException('Could not create Voucher' . $e->getMessage());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function delete($voucherId)
|
||
|
{
|
||
|
$voucher_orders = $this->getVoucherOrdersFromVoucher($voucherId, 1);
|
||
|
if (empty($voucher_orders)) {
|
||
|
$affectedRows = $this->db->fetchAffected('DELETE FROM voucher WHERE id = :id', ['id' => $voucherId]);
|
||
|
|
||
|
return $affectedRows === 1;
|
||
|
}
|
||
|
throw new RuntimeException('Voucher is allready associated with order(s)');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
*/
|
||
|
public function recalculateResidualValue($voucherId)
|
||
|
{
|
||
|
$residualValue = $this->getResidualValueFromVoucherId($voucherId);
|
||
|
$this->db->perform('UPDATE voucher SET voucher_residual_value = :voucher_residual_value WHERE id = :id'
|
||
|
, ['voucher_residual_value' => $residualValue, 'id' => $voucherId]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param array $voucher
|
||
|
* @param int $projectId
|
||
|
* @param float $value
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getArticleForPos($voucher, $projectId, $value)
|
||
|
{
|
||
|
$sql = '
|
||
|
SELECT
|
||
|
art.id,
|
||
|
art.nummer,
|
||
|
art.projekt,
|
||
|
art.name_de AS artikel,
|
||
|
art.kurztext_de,
|
||
|
art.umsatzsteuer,
|
||
|
art.rabatt AS rabattartikel,
|
||
|
art.rabatt_prozent,
|
||
|
art.anabregs_text,
|
||
|
IF(art.seriennummern=\'keine\',\'\',IFNULL(art.seriennummern,\'\')) AS seriennummern,
|
||
|
art.porto,
|
||
|
ifnull(art.keinrabatterlaubt,0) AS keinrabatterlaubt
|
||
|
FROM
|
||
|
artikel AS art
|
||
|
WHERE
|
||
|
art.id = :article_id
|
||
|
';
|
||
|
|
||
|
$row = $this->db->fetchRow($sql, [
|
||
|
'article_id' => $voucher['article_id'],
|
||
|
]);
|
||
|
|
||
|
$row['anabregs_text'] = $voucher['voucher_code'];
|
||
|
$row['keinrabatterlaubt'] = 1;
|
||
|
$row['rabatt_prozent'] = 0;
|
||
|
$row['rabatt'] = 0;
|
||
|
|
||
|
$erloes = '';
|
||
|
$steuersatz = null;
|
||
|
$steuertext = null;
|
||
|
$umsatzsteuerpos = null;
|
||
|
$this->app->erp->GetArtikelSteuer(
|
||
|
$voucher['article_id'],
|
||
|
0,
|
||
|
false,
|
||
|
$steuersatz,
|
||
|
$steuertext,
|
||
|
$erloes,
|
||
|
$umsatzsteuerpos,
|
||
|
null,
|
||
|
$projectId
|
||
|
);
|
||
|
$row['erloes'] = $erloes;
|
||
|
|
||
|
$row['umsatzsteuer'] = !empty($voucher['tax_name']) ? $voucher['tax_name'] : 'normal';
|
||
|
if ($row['umsatzsteuer'] === 'befreit') {
|
||
|
$row['tax'] = '0%';
|
||
|
} elseif ($row['umsatzsteuer'] === 'ermaessigt') {
|
||
|
$row['tax'] = round($this->app->erp->GetStandardSteuersatzErmaessigt($projectId), 2) . '%';
|
||
|
} else {
|
||
|
$row['tax'] = round($this->app->erp->GetStandardSteuersatzNormal($projectId), 2) . '%';
|
||
|
}
|
||
|
$row['preis'] = -$value;
|
||
|
|
||
|
return $row;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getValidTypes()
|
||
|
{
|
||
|
return $this->validtypes;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $validType
|
||
|
*
|
||
|
* @return string|null
|
||
|
*/
|
||
|
public function getValidToFromValidType($validType)
|
||
|
{
|
||
|
try {
|
||
|
$date = new DateTime(date('Y-m-d'));
|
||
|
if (strpos($validType, 'ThisYear') === 0) {
|
||
|
$date = new DateTime(date('Y-12-31'));
|
||
|
$plusYears = substr($validType, 8);
|
||
|
if (empty($plusYears)) {
|
||
|
return $date->format('Y-m-d');
|
||
|
}
|
||
|
if (strlen($plusYears) >= 5 && strpos($plusYears, 'Plus') === 0) {
|
||
|
$date->add(new DateInterval('P' . substr($plusYears, 4) . 'Y'));
|
||
|
|
||
|
return $date->format('Y-m-d');
|
||
|
}
|
||
|
} elseif (strlen($validType) > 4 && strpos($validType, 'Year') === 0) {
|
||
|
$plusYears = (int)substr($validType, 4);
|
||
|
if ($plusYears <= 0) {
|
||
|
return null;
|
||
|
}
|
||
|
$date->add(new DateInterval('P' . $plusYears . 'Y'));
|
||
|
|
||
|
return $date->format('Y-m-d');
|
||
|
} elseif (strlen($validType) > 5 && strpos($validType, 'Month') === 0) {
|
||
|
$plusMonth = (int)substr($validType, 5);
|
||
|
if ($plusMonth <= 0) {
|
||
|
return null;
|
||
|
}
|
||
|
$date->add(new DateInterval('P' . $plusMonth . 'M'));
|
||
|
|
||
|
return $date->format('Y-m-d');
|
||
|
}
|
||
|
} catch (Exception $e) {
|
||
|
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $columnname
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getValidTypeTranslationSql($columnname = 'vt.valid')
|
||
|
{
|
||
|
$sql = '';
|
||
|
foreach ($this->validtypes as $validkey => $validDescriotion) {
|
||
|
$sql .= sprintf('if(%s = \'%s\',\'%s\',', $columnname, $validkey, $validDescriotion);
|
||
|
}
|
||
|
$sql .= '\'\'' . str_repeat(')', count($this->validtypes));
|
||
|
|
||
|
return $sql;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $voucherId
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getCodeForDocumentByVoucherId($voucherId)
|
||
|
{
|
||
|
$voucher = $this->getById($voucherId);
|
||
|
|
||
|
return (int)$voucher['show_code_on_document'] === 1 ? $voucher['voucher_code'] : '';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $invoiceId
|
||
|
* @param int $positionId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function findCodesForDocumentByInvoiceIdAndPositionId(int $invoiceId, int $positionId): array
|
||
|
{
|
||
|
$sql =
|
||
|
'SELECT v.voucher_code
|
||
|
FROM `voucher` AS `v`
|
||
|
WHERE v.invoice_position_id = :invoice_position_id
|
||
|
AND v.invoice_id = :invoice_id
|
||
|
AND v.show_code_on_document = 1';
|
||
|
|
||
|
$results = $this->db->fetchAll(
|
||
|
$sql,
|
||
|
[
|
||
|
'invoice_position_id' => $positionId,
|
||
|
'invoice_id' => $invoiceId,
|
||
|
]
|
||
|
);
|
||
|
$codes = [];
|
||
|
if (!empty($results)) {
|
||
|
foreach ($results as $result) {
|
||
|
$codes[] = $result['voucher_code'];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $codes;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $invoiceId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getVouchersByInvoiceId($invoiceId)
|
||
|
{
|
||
|
return $this->db->fetchAll(
|
||
|
'SELECT v.* FROM voucher AS v WHERE v.invoice_id = :invoice_id',
|
||
|
['invoice_id' => $invoiceId]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $date
|
||
|
* @param int $projectId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getPosVouchersByDate($date, $projectId = 0)
|
||
|
{
|
||
|
return $this->db->fetchAll(
|
||
|
'SELECT v.*
|
||
|
FROM voucher AS v
|
||
|
INNER JOIN rechnung AS i ON v.invoice_id = i.id
|
||
|
INNER JOIN pos_order AS po ON i.id = po.rechnung
|
||
|
WHERE DATE(po.zeitstempel) = :date AND (po.projekt = :project_id OR 0 = :project_id)',
|
||
|
['date' => $date, 'project_id' => $projectId]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $date
|
||
|
* @param int $projectId
|
||
|
* @param string $status
|
||
|
* @param string $paymentType
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getPosVoucherSumByDateTax($date, $projectId = 0, $status = '', $paymentType = '')
|
||
|
{
|
||
|
return $this->db->fetchAll(
|
||
|
'SELECT SUM(
|
||
|
IF(
|
||
|
ip.umsatz_brutto_gesamt <> 0,
|
||
|
ip.umsatz_brutto_gesamt,
|
||
|
ip.menge*ip.preis*(1-ip.rabatt / 100)
|
||
|
* IF(
|
||
|
i.ust_befreit > 1 OR (i.ust_befreit = 1 AND i.ustid != \'\')
|
||
|
OR ip.umsatzsteuer = \'befreit\' OR ip.steuersatz = 0,
|
||
|
0, IF(ip.steuersatz > 0,ip.steuersatz,IF(ip.umsatzsteuer = \'ermaessigt\',
|
||
|
i.steuersatz_ermaessigt, i.steuersatz_normal))
|
||
|
)/ 100
|
||
|
)
|
||
|
) AS amount,
|
||
|
IF(
|
||
|
i.ust_befreit > 1 OR (i.ust_befreit = 1 AND i.ustid != \'\')
|
||
|
OR ip.umsatzsteuer = \'befreit\' OR ip.steuersatz = 0,
|
||
|
0, IF(ip.steuersatz > 0,ip.steuersatz,IF(ip.umsatzsteuer = \'ermaessigt\',
|
||
|
i.steuersatz_ermaessigt, i.steuersatz_normal))
|
||
|
) AS tax
|
||
|
FROM voucher AS v
|
||
|
INNER JOIN rechnung AS i ON v.invoice_id = i.id AND (i.status = :status OR :status = \'\')
|
||
|
AND (i.zahlungsweise = :payment OR :payment = \'\')
|
||
|
INNER JOIN rechnung_position AS ip ON i.id = ip.rechnung AND v.article_id = ip.artikel
|
||
|
INNER JOIN pos_order AS po ON i.id = po.rechnung
|
||
|
WHERE DATE(po.zeitstempel) = :date AND (po.projekt = :project_id OR 0 = :project_id)
|
||
|
GROUP BY tax
|
||
|
ORDER BY tax',
|
||
|
['date' => $date, 'project_id' => $projectId, 'status' => (String)$status, 'payment' => $paymentType]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param string $date
|
||
|
* @param int $projectId
|
||
|
* @param string $status
|
||
|
*
|
||
|
* @return float
|
||
|
*/
|
||
|
public function getPosVoucherSumByDate($date, $projectId = 0, $status = '')
|
||
|
{
|
||
|
return (float)$this->db->fetchValue(
|
||
|
"SELECT SUM(v.voucher_original_value)
|
||
|
FROM voucher AS v
|
||
|
INNER JOIN rechnung AS i ON v.invoice_id = i.id AND (i.status = :status OR :status = '')
|
||
|
INNER JOIN pos_order AS po ON i.id = po.rechnung
|
||
|
WHERE DATE(po.zeitstempel) = :date AND (po.projekt = :project_id OR 0 = :project_id)",
|
||
|
['date' => $date, 'project_id' => $projectId, 'status' => (String)$status]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $date
|
||
|
* @param int $projectId
|
||
|
* @param string $status
|
||
|
*
|
||
|
* @return float
|
||
|
*/
|
||
|
public function getReedemedPosSumByDate($date, $projectId = 0, $status = '')
|
||
|
{
|
||
|
return (float)$this->db->fetchValue(
|
||
|
"SELECT SUM(vo.voucher_value)
|
||
|
FROM pos_order AS po
|
||
|
INNER JOIN auftrag AS o ON po.auftrag = o.id
|
||
|
INNER JOIN rechnung AS i ON o.id = i.auftragid AND po.rechnung = i.id AND (i.status = :status OR :status = '')
|
||
|
INNER JOIN voucher_order AS vo
|
||
|
ON (o.id = vo.order_id AND vo.doctype <> 'rechnung' OR i.id = vo.voucher_id AND vo.doctype = 'rechnung')
|
||
|
WHERE DATE(po.zeitstempel) = :date AND (po.projekt = :project_id OR 0 = :project_id)",
|
||
|
['date' => $date, 'project_id' => $projectId, 'status' => (String)$status]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $invoiceId
|
||
|
* @param array $positionArr
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function createVoucherFromInvoicePositions($invoiceId, $positionArr)
|
||
|
{
|
||
|
if (empty($invoiceId) || empty($positionArr)) {
|
||
|
return $positionArr;
|
||
|
}
|
||
|
|
||
|
$positionIdKeyArr = [];
|
||
|
foreach ($positionArr as $row) {
|
||
|
$positionIdKeyArr[$row['position_id']] = $row;
|
||
|
}
|
||
|
|
||
|
$neededVouchers = $this->getNeededVouchersFromInvoice($invoiceId, $positionIdKeyArr);
|
||
|
|
||
|
if (empty($neededVouchers)) {
|
||
|
return $positionArr;
|
||
|
}
|
||
|
|
||
|
foreach ($neededVouchers as $neededVoucherKey => $neededVoucher) {
|
||
|
$template = $this->getTemplateFromId($neededVoucher['template_id']);
|
||
|
for ($i = 1; $i <= $neededVoucher['amount']; $i++) {
|
||
|
$neededVouchers[$neededVoucherKey]['voucherId'] = $this->createVoucherFromTemplate($invoiceId,
|
||
|
$neededVoucher['position_id'], $neededVoucher['price_gross'], $neededVoucher['currency'],
|
||
|
$template);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $neededVouchers;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $templateId
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getTemplateFromId($templateId)
|
||
|
{
|
||
|
$sql = 'SELECT * FROM voucher_template WHERE id = :id';
|
||
|
|
||
|
$ret = $this->db->fetchRow($sql, ['id' => $templateId]);
|
||
|
if ($ret['tax_name'] !== 'ermaessigt' && $ret['tax_name'] !== 'normal') {
|
||
|
$ret['tax_name'] = 'befreit';
|
||
|
}
|
||
|
|
||
|
return $ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $invoiceId
|
||
|
* @param int $invoicePositionId
|
||
|
* @param float $price
|
||
|
* @param string $currency
|
||
|
* @param array $template
|
||
|
*
|
||
|
* @return int
|
||
|
*/
|
||
|
public function createVoucherFromTemplate($invoiceId, $invoicePositionId, $price, $currency, $template)
|
||
|
{
|
||
|
if (empty($invoiceId) || empty($price) || empty($template)) {
|
||
|
return 0;
|
||
|
}
|
||
|
$code = $this->getNewVoucherCodeFromPattern($template['code_pattern']);
|
||
|
if (empty($code)) {
|
||
|
return 0;
|
||
|
}
|
||
|
$validFrom = null;
|
||
|
$validTo = $this->getValidToFromValidType($template['valid']);
|
||
|
if ($validTo !== null) {
|
||
|
$validFrom = date('Y-m-d');
|
||
|
}
|
||
|
$addressId = $this->db->fetchValue(
|
||
|
'SELECT adresse FROM rechnung WHERE id = :invoice_id LIMIT 1',
|
||
|
['invoice_id' => (int)$invoiceId]
|
||
|
);
|
||
|
|
||
|
return $this->create($code, $template['article_id'], $price, $invoiceId, $invoicePositionId,
|
||
|
$template['tax_name'], $currency, $validFrom, $validTo, $template['show_code_on_document'] ? true : false,
|
||
|
$template['only_for_customer'] ? true : false, $addressId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $invoiceId
|
||
|
* @param array $articleAmounts
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getNeededVouchersFromInvoice($invoiceId, $invoicePosData)
|
||
|
{
|
||
|
$neededVouchers = [];
|
||
|
if (empty($invoiceId) || empty($invoicePosData)) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
//amount_diff = invoice amount - amount of voucher codes for invoice position
|
||
|
$sql =
|
||
|
'SELECT
|
||
|
rp.id AS `position_id`,
|
||
|
rp.artikel AS `article_id`,
|
||
|
rp.menge - IFNULL(COUNT(v.id),0) AS `amount_diff`,
|
||
|
vt.id AS `template_id`
|
||
|
FROM `rechnung_position` AS `rp`
|
||
|
LEFT JOIN `voucher` AS `v` ON v.invoice_position_id = rp.id
|
||
|
INNER JOIN `voucher_template` AS `vt` ON vt.article_id = rp.artikel
|
||
|
WHERE rp.rechnung = :invoice_id
|
||
|
GROUP BY rp.id';
|
||
|
|
||
|
$voucherData = $this->db->fetchAll($sql, ['invoice_id' => $invoiceId]);
|
||
|
|
||
|
if (empty($voucherData)) {
|
||
|
return [];
|
||
|
}
|
||
|
foreach ($voucherData as $data) {
|
||
|
$positionId = $data['position_id'];
|
||
|
$priceGross = $invoicePosData[$positionId]['price_gross'];
|
||
|
$taxName = $invoicePosData[$positionId]['tax_name'];
|
||
|
if ($data['amount_diff'] > 0) {
|
||
|
$neededVouchers[] = [
|
||
|
'template_id' => $data['template_id'],
|
||
|
'price_gross' => $priceGross,
|
||
|
'amount' => $data['amount_diff'],
|
||
|
'tax_name' => $taxName,
|
||
|
'position_id' => $positionId,
|
||
|
];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $neededVouchers;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $count
|
||
|
* @param string $type
|
||
|
*
|
||
|
* @return null|string
|
||
|
*/
|
||
|
private function genCode($count, $type)
|
||
|
{
|
||
|
if ($count <= 0) {
|
||
|
return null;
|
||
|
}
|
||
|
$code = '';
|
||
|
if ($type === 'num') {
|
||
|
$chararr = $this->digits;
|
||
|
} elseif ($type === 'anum') {
|
||
|
$chararr = array_merge($this->digits, $this->alphas);
|
||
|
} elseif ($type === 'alpha') {
|
||
|
$chararr = $this->alphas;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
$upper = count($chararr) - 1;
|
||
|
for ($i = 0; $i < $count; $i++) {
|
||
|
$chr = $chararr[mt_rand(0, $upper)];
|
||
|
while ($i === 0 && $chr === '0') {
|
||
|
$chr = $chararr[mt_rand(0, $upper)];
|
||
|
}
|
||
|
$code .= $chr;
|
||
|
}
|
||
|
|
||
|
return $code;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $pattern
|
||
|
*
|
||
|
* @return string|null
|
||
|
*/
|
||
|
public function getNewVoucherCodeFromPattern($pattern)
|
||
|
{
|
||
|
$numcount = 0;
|
||
|
$subpattern = '';
|
||
|
$patterns = ['num', 'anum', 'alpha'];
|
||
|
foreach ($patterns as $patterntype) {
|
||
|
$plen = strlen($patterntype);
|
||
|
if (strpos($pattern, $patterntype) === 0) {
|
||
|
$numcount = (int)substr($pattern, $plen);
|
||
|
$subpattern = $patterntype;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($numcount <= 0) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
$code = $this->genCode($numcount, $subpattern);
|
||
|
if ($code === null) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
while (
|
||
|
$this->db->fetchValue('
|
||
|
SELECT id
|
||
|
FROM voucher
|
||
|
WHERE voucher_code = :code',
|
||
|
['code' => $code]
|
||
|
)
|
||
|
) {
|
||
|
$code = $this->genCode($numcount, $subpattern);
|
||
|
}
|
||
|
|
||
|
return $code;
|
||
|
}
|
||
|
}
|