Create module rechnungslauf, basic version
This commit is contained in:
@@ -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')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
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'];
|
||||
$beschreibung .= "<br>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 .= "<br>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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user