diff --git a/classes/Modules/SubscriptionCycle/Bootstrap.php b/classes/Modules/SubscriptionCycle/Bootstrap.php
index 8e5fdb0b..a27c4664 100644
--- a/classes/Modules/SubscriptionCycle/Bootstrap.php
+++ b/classes/Modules/SubscriptionCycle/Bootstrap.php
@@ -5,6 +5,7 @@ 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 +36,7 @@ final class Bootstrap
'SubscriptionCycleJobService' => 'onInitSubscriptionCycleJobService',
'SubscriptionCycleFullTask' => 'onInitSubscriptionCycleFullTask',
'TaskMutexService' => 'onInitTaskMutexService',
+ 'SubscriptionModule' => 'onInitSubscriptionModule'
];
}
@@ -60,20 +62,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 +204,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')
+ );
}
}
diff --git a/classes/Modules/SubscriptionCycle/Scheduler/SubscriptionCycleManualJobTask.php b/classes/Modules/SubscriptionCycle/Scheduler/SubscriptionCycleManualJobTask.php
index b7b4b03a..f7378baa 100644
--- a/classes/Modules/SubscriptionCycle/Scheduler/SubscriptionCycleManualJobTask.php
+++ b/classes/Modules/SubscriptionCycle/Scheduler/SubscriptionCycleManualJobTask.php
@@ -16,52 +16,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
) {
$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 +52,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 +69,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);
- }
-
}
diff --git a/classes/Modules/SubscriptionCycle/Service/SubscriptionCycleJobService.php b/classes/Modules/SubscriptionCycle/Service/SubscriptionCycleJobService.php
index 802d138f..5d5c106b 100644
--- a/classes/Modules/SubscriptionCycle/Service/SubscriptionCycleJobService.php
+++ b/classes/Modules/SubscriptionCycle/Service/SubscriptionCycleJobService.php
@@ -11,7 +11,7 @@ use Xentral\Modules\SubscriptionCycle\Exception\InvalidArgumentException;
final class SubscriptionCycleJobService
{
- private $db;
+ private Database $db;
/**
* SubscriptionCycleJobService constructor.
@@ -57,29 +57,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();
}
/**
diff --git a/classes/Modules/SubscriptionCycle/SubscriptionModule.php b/classes/Modules/SubscriptionCycle/SubscriptionModule.php
new file mode 100644
index 00000000..6adfcca6
--- /dev/null
+++ b/classes/Modules/SubscriptionCycle/SubscriptionModule.php
@@ -0,0 +1,101 @@
+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'];
+ $beschreibung .= "
Zeitraum: {$pos['start']} - {$pos['end']}";
+ $this->app->erp->AddRechnungPositionManuell($invoice, $pos['artikel'], $pos['preis'],
+ $pos['menge']*$pos['cycles'], $pos['bezeichnung'], $beschreibung, $pos['waehrung'], $pos['rabatt']);
+ }
+ $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'];
+ $beschreibung .= "
Zeitraum: {$pos['start']} - {$pos['end']}";
+ $this->app->erp->AddAuftragPositionManuell($orderid, $pos['artikel'], $pos['preis'],
+ $pos['menge']*$pos['cycles'], $pos['bezeichnung'], $beschreibung, $pos['waehrung'], $pos['rabatt']);
+ }
+ $this->app->erp->AuftragNeuberechnen($orderid);
+ $this->app->erp->BelegFreigabe('auftrag', $orderid);
+ }
+}
\ No newline at end of file
diff --git a/classes/Modules/SubscriptionCycle/SubscriptionModuleInterface.php b/classes/Modules/SubscriptionCycle/SubscriptionModuleInterface.php
index f30a97af..dea66b6c 100644
--- a/classes/Modules/SubscriptionCycle/SubscriptionModuleInterface.php
+++ b/classes/Modules/SubscriptionCycle/SubscriptionModuleInterface.php
@@ -8,36 +8,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;
}
diff --git a/upgrade/data/db_schema.json b/upgrade/data/db_schema.json
index fbfab4fd..db865632 100644
--- a/upgrade/data/db_schema.json
+++ b/upgrade/data/db_schema.json
@@ -98587,6 +98587,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",
diff --git a/www/pages/content/rechnungslauf_abos.tpl b/www/pages/content/rechnungslauf_abos.tpl
new file mode 100644
index 00000000..5a0a1bc9
--- /dev/null
+++ b/www/pages/content/rechnungslauf_abos.tpl
@@ -0,0 +1,8 @@
+
"
+ . ""
+ . " |