Merge pull request #52 from exciler/subscriptioncycle

Subscriptioncycle
This commit is contained in:
OpenXE-ERP 2023-03-13 12:59:50 +01:00 committed by GitHub
commit f02be869d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 604 additions and 222 deletions

View File

@ -1,10 +1,17 @@
<?php
/*
* SPDX-FileCopyrightText: 2022 Andreas Palm
* SPDX-FileCopyrightText: 2019 Xentral ERP Sorftware GmbH, Fuggerstrasse 11, D-86150 Augsburg
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
*/
declare(strict_types=1);
namespace Xentral\Modules\SubscriptionCycle;
use Aboabrechnung;
use Sabre\CalDAV\Subscriptions\Subscription;
use Xentral\Components\SchemaCreator\Collection\SchemaCollection;
use Xentral\Components\SchemaCreator\Schema\TableSchema;
use Xentral\Components\SchemaCreator\Type;
@ -35,6 +42,7 @@ final class Bootstrap
'SubscriptionCycleJobService' => 'onInitSubscriptionCycleJobService',
'SubscriptionCycleFullTask' => 'onInitSubscriptionCycleFullTask',
'TaskMutexService' => 'onInitTaskMutexService',
'SubscriptionModule' => 'onInitSubscriptionModule'
];
}
@ -60,20 +68,12 @@ final class Bootstrap
*/
public static function onInitSubscriptionCycleManualJobTask(ContainerInterface $container
): SubscriptionCycleManualJobTask {
$legacyApp = $container->get('LegacyApplication');
$subscriptionCycleModule = $legacyApp->loadModule('rechnungslauf');
$subscriptionModule = new Aboabrechnung($legacyApp);
$subscriptionModule->cronjob = true;
return new SubscriptionCycleManualJobTask(
$legacyApp,
$container->get('LegacyApplication'),
$container->get('Database'),
$container->get('TaskMutexService'),
$container->get('SubscriptionCycleJobService'),
$subscriptionCycleModule,
$subscriptionModule,
!empty($legacyApp->erp->GetKonfiguration('rechnungslauf_gruppen'))
$container->get('SubscriptionModule')
);
}
@ -210,22 +210,10 @@ final class Bootstrap
);
}
/**
* @param SchemaCollection $collection
*
* @return void
*/
public static function registerTableSchemas(SchemaCollection $collection): void
{
$subscriptionCycleJob = new TableSchema('subscription_cycle_job');
$subscriptionCycleJob->addColumn(Type\Integer::asAutoIncrement('id'));
$subscriptionCycleJob->addColumn(new Type\Integer('address_id'));
$subscriptionCycleJob->addColumn(new Type\Varchar('document_type', 32));
$subscriptionCycleJob->addColumn(new Type\Varchar('job_type', 32));
$subscriptionCycleJob->addColumn(new Type\Integer('printer_id'));
$subscriptionCycleJob->addColumn(new Type\Timestamp('created_at', 'CURRENT_TIMESTAMP'));
$subscriptionCycleJob->addIndex(new Index\Primary(['id']));
$subscriptionCycleJob->addIndex(new Index\Index(['address_id']));
$collection->add($subscriptionCycleJob);
public static function onInitSubscriptionModule(ContainerInterface $container): SubscriptionModule {
return new SubscriptionModule(
$container->get('LegacyApplication'),
$container->get('Database')
);
}
}

View File

@ -1,4 +1,9 @@
<?php
/*
* SPDX-FileCopyrightText: 2022 Andreas Palm
* SPDX-FileCopyrightText: 2019 Xentral ERP Sorftware GmbH, Fuggerstrasse 11, D-86150 Augsburg
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
*/
declare(strict_types=1);
@ -16,52 +21,33 @@ use Xentral\Modules\SubscriptionCycle\SubscriptionModuleInterface;
final class SubscriptionCycleManualJobTask
{
/** @var ApplicationCore $app */
private $app;
private ApplicationCore $app;
private Database $db;
private SubscriptionCycleJobService $cycleJobService;
private TaskMutexServiceInterface $taskMutexService;
private SubscriptionModuleInterface $subscriptionModule;
/** @var Database $db */
private $db;
/** @var SubscriptionCycleJobService $cycleJobService */
private $cycleJobService;
/** @var TaskMutexServiceInterface $taskMutexService */
private $taskMutexService;
/** @var SubscriptionCycleModuleInterface $subscriptionCycleModule */
private $subscriptionCycleModule;
/** @var SubscriptionModuleInterface $subscriptionModule */
private $subscriptionModule;
/** @var bool $useGroups */
private $useGroups;
/**
* SubscriptionCycleManualJobTask constructor.
*
* @param ApplicationCore $app
* @param Database $db
* @param SubscriptionCycleJobService $cycleJobService
* @param SubscriptionCycleModuleInterface $subscriptionCycleModule
* @param bool $useGroups
*/
/**
* SubscriptionCycleManualJobTask constructor.
*
* @param ApplicationCore $app
* @param Database $db
* @param TaskMutexServiceInterface $taskMutexService
* @param SubscriptionCycleJobService $cycleJobService
* @param SubscriptionModuleInterface $subscriptionModule
*/
public function __construct(
ApplicationCore $app,
Database $db,
TaskMutexServiceInterface $taskMutexService,
SubscriptionCycleJobService $cycleJobService,
SubscriptionCycleModuleInterface $subscriptionCycleModule,
SubscriptionModuleInterface $subscriptionModule,
bool $useGroups
SubscriptionModuleInterface $subscriptionModule
) {
$this->app = $app;
$this->db = $db;
$this->taskMutexService = $taskMutexService;
$this->cycleJobService = $cycleJobService;
$this->subscriptionCycleModule = $subscriptionCycleModule;
$this->subscriptionModule = $subscriptionModule;
$this->useGroups = $useGroups;
}
public function execute(): void
@ -71,77 +57,16 @@ final class SubscriptionCycleManualJobTask
}
$this->taskMutexService->setMutex('rechnungslauf_manual');
$jobs = $this->cycleJobService->listAll(100);
$simulatedDays = $this->getSimulatedDates($jobs);
if (empty($jobs)) {
return;
}
foreach (['auftrag', 'rechnung'] as $doctype) {
foreach ($simulatedDays as $simulatedDay) {
if ($simulatedDay === '') {
$simulatedDay = null;
} else {
try {
$simulatedDay = new DateTimeImmutable($simulatedDay);
} catch (Exception $exception) {
$simulatedDay = null;
}
}
$addresses = $this->getAddressesByTypeFromJobs($jobs, $doctype, $simulatedDay);
foreach ($jobs as $job) {
$job = $this->cycleJobService->getJob((int)$job['id']);
if (empty($job)) {
continue;
}
if ($job['document_type'] !== $doctype) {
continue;
}
if ($job['simulated_day'] === null && $simulatedDay !== null) {
continue;
}
if (
$job['simulated_day'] !== null
&& ($simulatedDay === null || $simulatedDay->format('Y-m-d') !== $job['simulated_day'])
) {
continue;
}
if (!in_array($job['address_id'], $addresses, false)) {
$this->cycleJobService->delete((int)$job['id']);
continue;
}
$simulatedDay = null;
if ($job['simulated_day'] !== null) {
try {
$simulatedDay = new DateTimeImmutable($job['simulated_day']);
} catch (Exception $exception) {
$simulatedDay = null;
}
}
if ($this->useGroups) {
$this->subscriptionCycleModule->generateAndSendSubscriptionCycleGroups(
$this->subscriptionModule,
[$job['address_id']],
$doctype,
$job['job_type'],
$job['printer_id'],
$simulatedDay
);
} else {
$this->subscriptionCycleModule->generateAndSendSubscriptionCycle(
$this->subscriptionModule,
[$job['address_id']],
$doctype,
$job['printer_id'],
$job['job_type'],
$simulatedDay
);
}
$this->cycleJobService->delete((int)$job['id']);
if ($this->taskMutexService->isTaskInstanceRunning('rechnungslauf')) {
return;
}
$this->taskMutexService->setMutex('rechnungslauf_manual');
}
}
foreach ($jobs as $job) {
switch ($job['document_type']) {
case 'rechnung':
$this->subscriptionModule->CreateInvoice((int)$job['address_id']);
break;
case 'auftrag':
$this->subscriptionModule->CreateOrder((int)$job['address_id']);
break;
}
$this->cycleJobService->delete((int)$job['id']);
}
}
@ -149,52 +74,4 @@ final class SubscriptionCycleManualJobTask
{
$this->taskMutexService->setMutex('rechnungslauf_manual', false);
}
/**
* @param array $jobs
* @param string $documentType
* @param DateTimeInterface|null $simulatedDay
*
* @return array
*/
private function getAddressesByTypeFromJobs(
array $jobs,
string $documentType,
?DateTimeInterface $simulatedDay = null
): array {
$addresses = [];
foreach ($jobs as $job) {
if ($job['document_type'] === $documentType) {
$addresses[] = (int)$job['address_id'];
}
}
if (empty($addresses)) {
return [];
}
$addressesWithSubscriptions = array_keys(
(array)$this->subscriptionModule->GetRechnungsArray($documentType, true)
);
return array_intersect($addresses, $addressesWithSubscriptions);
}
/**
* get all Dates from Setting "Vergangenes Datum für Abrechnungserstellung" to calc old Subscription cycles
*
* @param array $jobs
*
* @return array
*/
private function getSimulatedDates(array $jobs): array
{
$simulatedDates = [];
foreach ($jobs as $job) {
$simulatedDates[] = (string)$job['simulated_day'];
}
return array_unique($simulatedDates);
}
}

View File

@ -1,4 +1,9 @@
<?php
/*
* SPDX-FileCopyrightText: 2022 Andreas Palm
* SPDX-FileCopyrightText: 2019 Xentral ERP Sorftware GmbH, Fuggerstrasse 11, D-86150 Augsburg
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
*/
declare(strict_types=1);
@ -11,7 +16,7 @@ use Xentral\Modules\SubscriptionCycle\Exception\InvalidArgumentException;
final class SubscriptionCycleJobService
{
private $db;
private Database $db;
/**
* SubscriptionCycleJobService constructor.
@ -57,29 +62,27 @@ final class SubscriptionCycleJobService
* @param string $documentType
* @param string|null $jobType
* @param int|null $printerId
* @param DateTimeInterface|null $simulatedDay
*
* @throws InvalidArgumentException
*
* @return int
*/
public function create(int $addressId, string $documentType, ?string $jobType, ?int $printerId, ?DateTimeInterface $simulatedDay = null): int
public function create(int $addressId, string $documentType, ?string $jobType = null, ?int $printerId = null): int
{
$this->ensureDocumentType($documentType);
$this->db->perform(
'INSERT INTO `subscription_cycle_job`
(`address_id`, `document_type`, `job_type`, `printer_id`, `created_at`, `simulated_day`)
VALUES (:address_id, :document_type, :job_type, :printer_id, NOW(), :simulated_day)',
(`address_id`, `document_type`, `job_type`, `printer_id`, `created_at`)
VALUES (:address_id, :document_type, :job_type, :printer_id, NOW())',
[
'address_id' => $addressId,
'document_type' => $documentType,
'job_type' => $jobType,
'printer_id' => $printerId,
'simulated_day' => $simulatedDay === null ? null : $simulatedDay->format('Y-m-d'),
]
);
return (int)$this->db->lastInsertId();
return $this->db->lastInsertId();
}
/**

View File

@ -0,0 +1,115 @@
<?php
/*
* SPDX-FileCopyrightText: 2022 Andreas Palm
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
*/
namespace Xentral\Modules\SubscriptionCycle;
use ApplicationCore;
use DateTimeImmutable;
use DateTimeInterface;
use Xentral\Components\Database\Database;
class SubscriptionModule implements SubscriptionModuleInterface
{
private ApplicationCore $app;
private Database $db;
public function __construct(ApplicationCore $app, Database $db)
{
$this->app = $app;
$this->db = $db;
}
public function GetPositions(int $address, string $documentType, DateTimeInterface $calculationDate = null): array
{
if ($calculationDate === null)
$calculationDate = new DateTimeImmutable('today');
$sql = "SELECT
aa.id,
@start := GREATEST(aa.startdatum, aa.abgerechnetbis) as start,
@end := IF(aa.enddatum = '0000-00-00' OR aa.enddatum > :calcdate, :calcdate, aa.enddatum) as end,
@cycles := CASE
WHEN aa.preisart = 'monat' THEN
TIMESTAMPDIFF(MONTH, @start, @end)
WHEN aa.preisart = 'jahr' THEN
TIMESTAMPDIFF(YEAR, @start, @end)
WHEN aa.preisart = '30tage' THEN
FLOOR(TIMESTAMPDIFF(DAY, @start, @end) / 30)
END+1 as cycles,
CASE
WHEN aa.preisart = 'monat' THEN
DATE_ADD(@start, INTERVAL @cycles MONTH)
WHEN aa.preisart = 'jahr' THEN
DATE_ADD(@start, INTERVAL @cycles YEAR)
WHEN aa.preisart = '30tage' THEN
DATE_ADD(@start, INTERVAL @cycles*30 DAY )
END as newend,
aa.preisart,
aa.adresse,
aa.preis,
aa.rabatt,
aa.bezeichnung,
aa.beschreibung,
aa.artikel,
aa.menge,
aa.waehrung
FROM abrechnungsartikel aa
JOIN artikel a on aa.artikel = a.id
WHERE aa.dokument = :doctype
AND greatest(aa.startdatum, aa.abgerechnetbis) <= :calcdate
AND (aa.enddatum = '0000-00-00' OR aa.abgerechnetbis < aa.enddatum)
AND aa.adresse = :address";
return $this->db->fetchAll($sql, [
'doctype' => $documentType,
'calcdate' => $calculationDate->format('Y-m-d'),
'address' => $address]);
}
public function CreateInvoice(int $address, DateTimeInterface $calculationDate = null) {
$positions = $this->GetPositions($address, 'rechnung', $calculationDate);
if(empty($positions))
return;
$invoice = $this->app->erp->CreateRechnung($address);
$this->app->erp->LoadRechnungStandardwerte($invoice, $address);
foreach ($positions as $pos) {
$beschreibung = $pos['beschreibung'];
$starts = DateTimeImmutable::createFromFormat('Y-m-d', $pos['start'])->format('d.m.Y');
$newends = DateTimeImmutable::createFromFormat('Y-m-d', $pos['newend'])->format('d.m.Y');
$beschreibung .= "<br>Zeitraum: $starts - $newends";
$this->app->erp->AddRechnungPositionManuell($invoice, $pos['artikel'], $pos['preis'],
$pos['menge']*$pos['cycles'], $pos['bezeichnung'], $beschreibung, $pos['waehrung'], $pos['rabatt']);
$this->db->exec("UPDATE abrechnungsartikel SET abgerechnetbis='{$pos['newend']}' WHERE id={$pos['id']}");
}
$this->app->erp->RechnungNeuberechnen($invoice);
//$this->app->erp->BelegFreigabe('rechnung', $invoice);
}
public function CreateOrder(int $address, DateTimeInterface $calculationDate = null) {
$positions = $this->GetPositions($address, 'auftrag', $calculationDate);
if(empty($positions))
return;
$orderid = $this->app->erp->CreateAuftrag($address);
$this->app->erp->LoadAuftragStandardwerte($orderid, $address);
foreach ($positions as $pos) {
$beschreibung = $pos['beschreibung'];
$starts = DateTimeImmutable::createFromFormat('Y-m-d', $pos['start'])->format('d.m.Y');
$newends = DateTimeImmutable::createFromFormat('Y-m-d', $pos['newend'])->format('d.m.Y');
$beschreibung .= "<br>Zeitraum: $starts - $newends";
$this->app->erp->AddAuftragPositionManuell($orderid, $pos['artikel'], $pos['preis'],
$pos['menge']*$pos['cycles'], $pos['bezeichnung'], $beschreibung, $pos['waehrung'], $pos['rabatt']);
$this->db->exec("UPDATE abrechnungsartikel SET abgerechnetbis='{$pos['newend']}' WHERE id={$pos['id']}");
}
$this->app->erp->AuftragNeuberechnen($orderid);
//$this->app->erp->BelegFreigabe('auftrag', $orderid);
}
}

View File

@ -1,6 +1,8 @@
<?php
declare(strict_types=1);
/*
* SPDX-FileCopyrightText: 2022 Andreas Palm
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
*/
namespace Xentral\Modules\SubscriptionCycle;
@ -8,36 +10,7 @@ use DateTimeInterface;
interface SubscriptionModuleInterface
{
/**
* @param int $customer
* @param string $documentType
*
* @return mixed
*/
public function RechnungKunde($customer, $documentType);
/**
* @param $customer
* @param $invoiceGroupKey
* @param $key
*
* @return mixed
*/
public function AuftragImportAbo($customer, $invoiceGroupKey, $key);
/**
* @param $customer
* @param $invoiceGroupKey
* @param $key
*
* @return mixed
*/
public function RechnungImportAbo($customer, $invoiceGroupKey, $key);
/**
* @param string $documentType
*
* @return array|null
*/
public function GetRechnungsArray($documentType);
public function CreateInvoice(int $address, DateTimeInterface $calculationDate = null);
public function CreateOrder(int $address, DateTimeInterface $calculationDate = null);
public function GetPositions(int $address, string $documentType, DateTimeInterface $calculationDate = null): array;
}

View File

@ -98692,6 +98692,92 @@
}
]
},
{
"name": "subscription_cycle_job",
"type": "BASE TABLE",
"columns": [
{
"Field": "id",
"Type": "int(11)",
"Collation": null,
"Null": "NO",
"Key": "PRI",
"Default": "",
"Extra": "auto_increment",
"Privileges": "select,insert,update,references",
"Commant": ""
},
{
"Field": "address_id",
"Type": "int(11)",
"Collation": null,
"Null": "NO",
"Key": "MUL",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Commant": ""
},
{
"Field": "document_type",
"Type": "varchar(32)",
"Collation": "utf8mb3_general_ci",
"Null": "NO",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Commant": ""
},
{
"Field": "job_type",
"Type": "varchar(32)",
"Collation": "utf8mb3_general_ci",
"Null": "YES",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Commant": ""
},
{
"Field": "printer_id",
"Type": "int(11)",
"Collation": "",
"Null": "YES",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Commant": ""
},
{
"Field": "created_at",
"Type": "timestamp",
"Collation": "",
"Null": "NO",
"Key": "",
"Default": "current_timestamp()",
"Extra": "",
"Privileges": "select,insert,update,references",
"Commant": ""
}
],
"keys": [
{
"Key_name": "PRIMARY",
"columns": [
"id"
]
},
{
"Key_name": "address",
"columns": [
"address_id"
]
}
]
},
{
"name": "supersearch_index_group",
"type": "BASE TABLE",

View File

@ -0,0 +1,12 @@
<!--
SPDX-FileCopyrightText: 2022 Andreas Palm
SPDX-License-Identifier: LicenseRef-EGPL-3.1
-->
<div id="tabs">
<ul>
<li></li>
</ul>
<div class="ui-tabs-panel">
[TAB1]
</div>
</div>

View File

@ -0,0 +1,40 @@
<!--
SPDX-FileCopyrightText: 2022 Andreas Palm
SPDX-License-Identifier: LicenseRef-EGPL-3.1
-->
<div id="tabs">
<ul>
<li><a href="#tabs-1">Rechnungen</a></li>
<li><a href="#tabs-2">Aufträge</a></li>
</ul>
<div id="tabs-1">
[MESSAGE_INVOICES]
<form method="post" action="#">
[TAB_INVOICES]
<fieldset>
<legend>{|Stapelverarbeitung|}</legend>
<input type="checkbox" id="auswahlalle" onchange="alleauswaehlen('#rechnungslauf_invoices');" />&nbsp;{|alle markieren|}
<input type="submit" class="btnBlue" name="createInvoices" value="{|ausf&uuml;hren|}" />
</fieldset>
</form>
</div>
<div id="tabs-2">
[MESSAGE_ORDERS]
<form method="post" action="#">
[TAB_ORDERS]
<fieldset>
<legend>{|Stapelverarbeitung|}</legend>
<input type="checkbox" id="auswahlalle" onchange="alleauswaehlen('#rechnungslauf_orders');" />&nbsp;{|alle markieren|}
<input type="submit" class="btnBlue" name="createOrders" value="{|ausf&uuml;hren|}" />
</fieldset>
</form>
</div>
</div>
<script>
function alleauswaehlen(target)
{
var wert = $('#auswahlalle').prop('checked');
$(target).find(':checkbox').prop('checked',wert);
}
</script>

View File

@ -1,3 +1,8 @@
<!--
SPDX-FileCopyrightText: 2022 Andreas Palm
SPDX-FileCopyrightText: 2019 Xentral ERP Sorftware GmbH, Fuggerstrasse 11, D-86150 Augsburg
SPDX-License-Identifier: LicenseRef-EGPL-3.1
-->
<fieldset>
<legend>[SUBHEADING]</legend>
@ -8,7 +13,7 @@
<th>{|Menge|}</th>
<th>{|Einzelpreis (netto)|}</th>
<th>{|Rabatt|}</th>
<th>{|UST|}</th>
<th>{|Zyklen|}</th>
<th>{|Gesamtpreis (netto)|}</th>
<th>{|Währung|}</th>
</tr>

283
www/pages/rechnungslauf.php Normal file
View File

@ -0,0 +1,283 @@
<?php
/*
* SPDX-FileCopyrightText: 2022 Andreas Palm
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
*/
use Xentral\Modules\SubscriptionCycle\Service\SubscriptionCycleJobService;
use Xentral\Modules\SubscriptionCycle\SubscriptionModule;
class Rechnungslauf {
/** @var Application $app */
protected $app;
/**
* @param Application $app
* @param string $name
* @param array $erlaubtevars
*
* @return array
*/
public static function TableSearch($app, $name, $erlaubtevars)
{
// in dieses switch alle lokalen Tabellen (diese Live Tabellen mit Suche etc.) für dieses Modul
switch($name)
{
case 'rechnungslauf_invoices':
case 'rechnungslauf_orders':
if ($name == 'rechnungslauf_invoices')
$doctype = 'rechnung';
else
$doctype = 'auftrag';
$allowed['rechnungslauf'] = ['rechnungslauf'];
$heading = array('', '', 'Kunden Nr.', 'Firma/Name', 'Anschreiben', 'E-Mail', 'Projekt', 'Von', 'Bis', 'Betrag netto', 'Men&uuml;');
$width = ['1%', '1%', '10%', '20%', '10%', '10%', '10%', '10%', '10%', '10%', '1%'];
$findcols = [
'',
'',
'adr.kundennummer',
'adr.name',
'adr.anschreiben',
"adr.email",
'p.abkuerzung',
null,
null,
null,
null
];
$searchsql = ['adr.kundennummer', 'adr.name', 'adr.email'];
$numbercols = [2, 10];
$alignright = [3, 10];
$datecols = [7, 8];
$defaultorder = 3;
$defaultorderdesc = 0;
$sumcol = [10];
$menu = '<table cellpadding="0" cellspacing="0">';
$menu .= '<tr>';
$menu .= '<td nowrap>';
$menu .= '<a href="index.php?module=adresse&action=artikel&id=%value%">';
$menu .= '<img src="themes/' . $app->Conf->WFconf['defaulttheme'] . '/images/forward.svg" border="0">';
$menu .= '</a>';
$menu .= '</td>';
$menu .= '</tr>';
$menu .= '</table>';
$calcdate = new \DateTimeImmutable('today');
$scalcdate = $calcdate->format('Y-m-d');
$where = " aa.id > 0
AND aa.dokument = '$doctype'
AND greatest(aa.startdatum, aa.abgerechnetbis) < '$scalcdate'
AND (aa.enddatum = '0000-00-00' OR aa.abgerechnetbis < aa.enddatum)";
$sql = "SELECT SQL_CALC_FOUND_ROWS
adr.id,
'<img src=\"./themes/new/images/details_open.png\" class=\"details\">' as open,
concat('<input type=\"checkbox\" name=\"selection[]\" value=\"',adr.id,'\" />') as auswahl,
adr.kundennummer,
adr.name,
adr.anschreiben,
adr.email,
p.abkuerzung,
GROUP_CONCAT(DATE_FORMAT(@start := GREATEST(aa.startdatum, aa.abgerechnetbis),'%d.%m.%Y') SEPARATOR '<br>') as start,
GROUP_CONCAT(DATE_FORMAT(
@end := CASE
WHEN aa.preisart = 'monat' THEN
DATE_ADD(@start, INTERVAL TIMESTAMPDIFF(MONTH, @start, IF(aa.enddatum = '0000-00-00' OR aa.enddatum > '$scalcdate', '$scalcdate', aa.enddatum))+1 MONTH)
WHEN aa.preisart = 'jahr' THEN
DATE_ADD(@start, INTERVAL TIMESTAMPDIFF(YEAR, @start, IF(aa.enddatum = '0000-00-00' OR aa.enddatum > '$scalcdate', '$scalcdate', aa.enddatum))+1 YEAR)
WHEN aa.preisart = '30tage' THEN
DATE_ADD(@start, INTERVAL (FLOOR(TIMESTAMPDIFF(DAY, @start, IF(aa.enddatum = '0000-00-00' OR aa.enddatum > '$scalcdate', '$scalcdate', aa.enddatum)) / 30)+1)*30 DAY )
END, '%d.%m.%Y') SEPARATOR '<br>') as end,
SUM((100-aa.rabatt)/100 * aa.preis * aa.menge *
(CASE
WHEN aa.preisart = 'monat' THEN
TIMESTAMPDIFF(MONTH, @start, @end)
WHEN aa.preisart = 'jahr' THEN
TIMESTAMPDIFF(YEAR, @start, @end)
WHEN aa.preisart = '30tage' THEN
FLOOR(TIMESTAMPDIFF(DAY, @start, @end) / 30)
END
)
) as amount,
adr.id
FROM abrechnungsartikel aa
JOIN artikel a ON aa.artikel = a.id
JOIN adresse adr ON aa.adresse = adr.id
LEFT JOIN projekt p ON aa.projekt = p.id";
$groupby = " GROUP BY aa.adresse, aa.projekt";
$count = "SELECT count(aa.id)
FROM `abrechnungsartikel` AS `aa`
WHERE $where $groupby";
$menucol = 10;
$moreinfo = true;
break;
case 'rechnungslauf_abos':
$allowed['rechnungslauf'] = ['abos'];
$heading = array(
'Kunde',
'Kunden Nr.',
'Bezeichnung',
'Nummer',
'Abgerechnet bis',
'Enddatum',
'Preis',
'Rabatt',
'Menge',
'Art',
'Zahlperiode',
'Zahlweise',
'Dokument',
'Men&uuml;');
$width = ['10%','5%','15%','1','1','1','1','1','1','1','1','1','1','1'];
$findcols = [
'ad.name',
'ad.kundennummer',
'aa.bezeichnung',
'a.nummer',
"DATE_FORMAT(aa.abgerechnetbis, '%d.%m.%Y')",
'aa.enddatum',
'aa.preis',
'aa.rabatt',
'aa.menge',
'aa.preisart',
'aa.zahlzyklus',
'',
'aa.dokument'
];
$searchsql = ['ad.name', 'aa.bezeichnung'];
$numbercols = [0];
$alignright = [7];
$datecols = [5,6];
$defaultorder = 1;
$defaultorderdesc = 0;
$menu = "<table cellpadding=0 cellspacing=0><tr><td nowrap>"
. "<a href=\"index.php?module=adresse&action=artikel&id=%value%\">"
. "<img src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/forward.svg\" border=\"0\"></a>"
. "&nbsp;</td></tr></table>";
$where = " aa.id > 0 AND (aa.enddatum = '0000-00-00' OR aa.abgerechnetbis < aa.enddatum) ";
$sql = "SELECT SQL_CALC_FOUND_ROWS aa.id, ad.name, ad.kundennummer,
aa.bezeichnung, a.nummer, DATE_FORMAT(aa.abgerechnetbis, '%d.%m.%Y'),
DATE_FORMAT(aa.enddatum, '%d.%m.%Y'),
".$app->erp->FormatPreis('aa.preis', 2).", aa.rabatt, aa.menge,
aa.preisart, aa.zahlzyklus, '', aa.dokument, ad.id
FROM `abrechnungsartikel` AS `aa`
LEFT JOIN `adresse` AS `ad` ON aa.adresse = ad.id
LEFT JOIN `artikel` AS `a` ON aa.artikel = a.id";
$count = "SELECT count(aa.id)
FROM `abrechnungsartikel` AS `aa`
WHERE $where";
break;
}
$erg = [];
foreach($erlaubtevars as $k => $v) {
if(isset($$v)) {
$erg[$v] = $$v;
}
}
return $erg;
}
/**
* Rechnungslauf constructor.
*
* @param Application $app
* @param bool $intern
*/
public function __construct($app, $intern = false) {
$this->app = $app;
if($intern) {
return;
}
$this->app->ActionHandlerInit($this);
// ab hier alle Action Handler definieren die das Modul hat
$this->app->ActionHandler('rechnungslauf', 'ActionList');
$this->app->ActionHandler('abos', 'ActionAbos');
$this->app->ActionHandler('minidetail', 'ActionMinidetail');
$this->app->ActionHandlerListen($app);
}
public function MenuList() {
$this->app->erp->Headlines("Abolauf");
$this->app->erp->MenuEintrag("index.php?module=rechnungslauf&action=rechnungslauf", "&Uuml;bersicht");
$this->app->erp->MenuEintrag("index.php?module=rechnungslauf&action=abos", "gebuchte Abos");
$this->app->erp->MenuEintrag("index.php?module=rechnungslauf&action=einstellungen", "Einstellungen");
}
public function ActionList() {
/** @var SubscriptionModule $module */
$this->MenuList();
$this->app->YUI->TableSearch("TAB_INVOICES", 'rechnungslauf_invoices','show', '', '', basename(__FILE__), __CLASS__);
$this->app->YUI->TableSearch("TAB_ORDERS", 'rechnungslauf_orders','show', '', '', basename(__FILE__), __CLASS__);
if ($this->app->Secure->GetPOST('createInvoices') !== '') {
$selection = $this->app->Secure->GetPOST('selection');
/** @var SubscriptionCycleJobService $subscriptionCycleJobService */
$subscriptionCycleJobService = $this->app->Container->get('SubscriptionCycleJobService');
foreach ($selection as $value) {
$subscriptionCycleJobService->deleteJobsByAddressIdAndDoctype($value, 'rechnung');
$subscriptionCycleJobService->create($value, 'rechnung');
$this->app->Tpl->addMessage('info', 'Die Rechnungen werden nun im Hintergrund erstellt', false, 'MESSAGE_INVOICES');
}
}
else if ($this->app->Secure->GetPOST('createOrders') !== '') {
$selection = $this->app->Secure->GetPOST('selection');
/** @var SubscriptionCycleJobService $subscriptionCycleJobService */
$subscriptionCycleJobService = $this->app->Container->get('SubscriptionCycleJobService');
foreach ($selection as $value) {
$subscriptionCycleJobService->deleteJobsByAddressIdAndDoctype($value, 'auftrag');
$subscriptionCycleJobService->create($value, 'auftrag');
$this->app->Tpl->addMessage('info', 'Die Aufträge werden nun im Hintergrund erstellt', false, 'MESSAGE_ORDERS');
}
}
$this->app->Tpl->Parse('PAGE', 'rechnungslauf_list.tpl');
}
public function ActionAbos() {
$this->MenuList();
$this->app->YUI->TableSearch("TAB1", 'rechnungslauf_abos', 'show', '', '', basename(__FILE__), __CLASS__);
$this->app->Tpl->Parse('PAGE', 'rechnungslauf_abos.tpl');
}
public function ActionMinidetail() {
/** @var SubscriptionModule $module */
$module = $this->app->Container->get('SubscriptionModule');
$address = $this->app->Secure->GetGET('id');
$pos = $module->GetPositions($address, 'rechnung');
foreach ($pos as $p) {
$row = '<tr>';
$row .= sprintf('<td>%s</td>', $p['bezeichnung']);
$row .= sprintf('<td>%s</td>', $p['menge']);
$row .= sprintf('<td style="text-align: right">%s</td>',
$this->app->erp->number_format_variable($p['preis'], 2));
$row .= sprintf('<td>%s</td>', $p['rabatt']);
$row .= sprintf('<td>%s</td>', $p['cycles']);
$row .= sprintf('<td style="text-align: right">%s</td>',
$this->app->erp->number_format_variable($p['preis']*$p['menge']*$p['cycles'], 2));
$row .= sprintf('<td>%s</td>', $p['waehrung']);
$row .= '</tr>';
$this->app->Tpl->Add('INHALT', $row);
}
$this->app->Tpl->Set('SUBHEADING', 'Kunde');
$this->app->Tpl->Output('rechnungslauf_minidetail.tpl');
$this->app->ExitXentral();
}
}