WIP Contract/Billing/Invoice 2024-06-28
This commit is contained in:
@@ -33,8 +33,20 @@ $pagination_entity_name = "Billingrecords";
|
||||
<div class="row">
|
||||
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_owner">Kundennummer</label>
|
||||
<input type="text" class="form-control" name="filter[customer_number]" id="filter_street" value="<?=(array_key_exists("customer_number", $filter)) ? $filter['customer_number'] : ""?>"/>
|
||||
<label class="form-label" for="filter_customer_number">Kundennummer</label>
|
||||
<input type="text" class="form-control" name="filter[customer_number]" id="filter_customer_number" value="<?=(array_key_exists("customer_number", $filter)) ? $filter['customer_number'] : ""?>"/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_customer">Kunde</label>
|
||||
<input type="text" class="form-control" name="filter[customer]" id="filter_customer" value="<?=(array_key_exists("customer", $filter)) ? $filter['customer'] : ""?>"/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_address">Adresse</label>
|
||||
<input type="text" class="form-control" name="filter[address]" id="filter_address" value="<?=(array_key_exists("address", $filter)) ? $filter['address'] : ""?>"/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_product">Produkt</label>
|
||||
<input type="text" class="form-control" name="filter[product]" id="filter_product" value="<?=(array_key_exists("product", $filter)) ? $filter['product'] : ""?>"/>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<label class="form-label" for="filter_show_credit">Gutschriften</label>
|
||||
@@ -74,7 +86,7 @@ $pagination_entity_name = "Billingrecords";
|
||||
</div>
|
||||
<div class="float-right">
|
||||
<a class="btn btn-outline-primary mb-2" href="<?=self::getUrl("Billing", "importContracts")?>">
|
||||
<i class="fas fa-fw fa-file-import"></i> Verrechenbare Contracts importieren
|
||||
<i class="fas fa-fw fa-file-import"></i> Aktuell verrechenbare Contracts neu importieren
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,23 +104,24 @@ $pagination_entity_name = "Billingrecords";
|
||||
<th>Vertragsinhaber</th>
|
||||
<th>Rechnungsadresse</th>
|
||||
<th>Kundennummer</th>
|
||||
<th>Einzug</th>
|
||||
<th>Zustellung</th>
|
||||
<th>Bankdaten</th>
|
||||
<th>Produkt</th>
|
||||
<th>Anzahl</th>
|
||||
<th>Preis</th>
|
||||
<th>Preis Setup</th>
|
||||
<th>Zahlung</th>
|
||||
<th>Zustellung</th>
|
||||
<th>Bankdaten</th>
|
||||
|
||||
<th></th>
|
||||
</tr>
|
||||
<?php foreach($billings as $billing): ?>
|
||||
<tr>
|
||||
<td><a href="<?=self::getUrl("Contract", "view", ["contract_id" => $billing->contract_id])?>" target="_blank"><?=$billing->contract_id?></a></td>
|
||||
<td><?=$billing->start_date?> - <?=$billing->end_date?></td>
|
||||
<td><?=$billing->start_date?> -<br /><?=$billing->end_date?></td>
|
||||
<td>
|
||||
<?=$billing->contract->owner->getCompanyOrName()?><br />
|
||||
<?=$billing->contract->owner->street?><br />
|
||||
<?=$billing->contract->owner->zip?> <?=$billing->contract->owner->city?>
|
||||
<?=$billing->contract->owner->zip?> <?=$billing->contract->owner->city?><br />
|
||||
<?=$billing->contract->owner->country->name?>
|
||||
</td>
|
||||
<td>
|
||||
@@ -119,6 +132,17 @@ $pagination_entity_name = "Billingrecords";
|
||||
<?=$billing->country?>
|
||||
</td>
|
||||
<td><?=$billing->customer_number?></td>
|
||||
<td>
|
||||
<?=$billing->product_name?><?=($billing->matchcode) ? " (".$billing->matchcode.")" : ""?>
|
||||
<?php if($billing->product_info): ?>
|
||||
<div class="pl-2">
|
||||
<?=$billing->product_info?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?=($billing->amount / (int)$billing->amount > 1) ? number_format($billing->amount,3,",",".") : (int)$billing->amount?></td>
|
||||
<td class="<?=($billing->price < 0) ? "text-danger" : ""?>">€ <?=number_format($billing->price,4,",",".")?></td>
|
||||
<td class="<?=($billing->price_setup < 0) ? "text-danger" : ""?>">€ <?=number_format($billing->price_setup,4,",",".")?></td>
|
||||
<td><?=($billing->billing_type == "sepa") ? "SEPA" : ""?></td>
|
||||
<td><?=($billing->billing_delivery == "email") ? "Email" : "Papier"?></td>
|
||||
<td>
|
||||
@@ -129,17 +153,7 @@ $pagination_entity_name = "Billingrecords";
|
||||
BIC: <?=$billing->bank_account_bic?><br />
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?=$billing->product_name?><?=($billing->matchcode) ? " (".$billing->matchcode.")" : ""?>
|
||||
<?php if($billing->product_info): ?>
|
||||
<div class="pl-2">
|
||||
<?=$billing->product_info?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?=number_format($billing->amount,3,",",".")?></td>
|
||||
<td>€ <?=number_format($billing->price,4,",",".")?></td>
|
||||
<td>€ <?=number_format($billing->price_setup,4,",",".")?></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
@@ -148,8 +148,9 @@
|
||||
<label class="col-lg-2 col-form-label" for="billing_period">Verrechnungsperiode</label>
|
||||
<div class="col-lg-10">
|
||||
<select class="form-control" name="billing_period" id="billing_period" placeholder="Verrechnungsperiode">
|
||||
<option value="1" <?=($product->billing_period == 1) ? "selected='selected'" : ""?>>Monatlich</option>
|
||||
<option value="12" <?=($product->billing_period == 12) ? "selected='selected'" : ""?>>Jährlich</option>
|
||||
<option value="0" <?=($contract && $contract->billing_period == 0) ? "selected='selected'" : ""?>>Einmalig</option>
|
||||
<option value="1" <?=($contract && $contract->billing_period == 1) ? "selected='selected'" : ""?>>Monatlich</option>
|
||||
<option value="12" <?=($contract && $contract->billing_period == 12) ? "selected='selected'" : ""?>>Jährlich</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -131,15 +131,7 @@
|
||||
<td class="<?=($contract->isCancelled()) ? "canceled" : "" ?> <?=(!$contract->isFinished()) ? "not-finished" : "" ?> <?=($contract->price < 0) ? "text-danger" : ""?>">€ <?=number_format($contract->price,4,",",".")?></td>
|
||||
<td class="<?=($contract->isCancelled()) ? "canceled" : "" ?> <?=(!$contract->isFinished()) ? "not-finished" : "" ?> <?=($contract->price_setup < 0) ? "text-danger" : ""?>">€ <?=number_format($contract->price_setup,4,",",".")?></td>
|
||||
<td class="<?=($contract->isCancelled()) ? "canceled" : "" ?> <?=(!$contract->isFinished()) ? "not-finished" : "" ?>">
|
||||
<?php if($contract->billing_period == 1): ?>
|
||||
monatlich
|
||||
<?php elseif($contract->billing_period == 24): ?>
|
||||
biennal
|
||||
<?php elseif($contract->billing_period == 36): ?>
|
||||
triennal
|
||||
<?php elseif($contract->billing_period): ?>
|
||||
<?=(12 / $contract->billing_period)?>x Jährlich
|
||||
<?php endif; ?>
|
||||
<?=__($contract->billing_period, "billing_period")?>
|
||||
</td>
|
||||
<td class="text-monospace <?=(!$contract->isFinished()) ? "not-finished" : "" ?>"><?=($contract->finish_date) ? date('d.m.Y', $contract->finish_date) : ""?></td>
|
||||
<td class="text-monospace"><?=($contract->cancel_date) ? date('d.m.Y', $contract->cancel_date) : ""?></td>
|
||||
|
||||
@@ -136,12 +136,12 @@
|
||||
<?php endif; ?>
|
||||
<tr>
|
||||
<th>Vertragsinhaber:</th>
|
||||
<td><a href="<?=self::getUrl("Address", "View", ["id" => $contract->owner_id])?>"><?=$contract->owner->getCompanyOrName()?> [<?=$contract->owner->customer_number?>]</a></td>
|
||||
<td><a href="<?=self::getUrl("Address", "View", ["id" => $contract->owner_id])?>"><?=$contract->owner->getCompanyOrName()?></a> [<?=$contract->owner->customer_number?>]</td>
|
||||
</tr>
|
||||
<?php if($contract->billingaddress_id): ?>
|
||||
<tr>
|
||||
<th>Rechnungsempfänger:</th>
|
||||
<td><a href="<?=self::getUrl("Address", "View", ["id" => $contract->billingaddress_id])?>"><?=$contract->billingaddress->getCompanyOrName()?> [<?=$contract->billingaddress->customer_number?>]</a></td>
|
||||
<td><a href="<?=self::getUrl("Address", "View", ["id" => $contract->billingaddress_id])?>"><?=$contract->billingaddress->getCompanyOrName()?></a> [<?=$contract->billingaddress->customer_number?>]</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<tr>
|
||||
@@ -160,22 +160,42 @@
|
||||
<th>Externes Produkt:</th>
|
||||
<td><?=($contract->product_external) ? "Ja" : "Nein"?></td>
|
||||
</tr><tr>
|
||||
<th>Setup Preis:</th>
|
||||
<td class="<?=($contract->price_setup < 0) ? "text-danger" : ""?>">€ <?=$contract->price_setup?></td>
|
||||
</tr><tr>
|
||||
<th>Preis Periodisch:</th>
|
||||
<td class="<?=($contract->price < 0) ? "text-danger" : ""?>">€ <?=$contract->price?></td>
|
||||
</tr><tr>
|
||||
<th>Verrechnungsperiode:</th>
|
||||
<td>
|
||||
<?=($contract->billing_period == 1) ? "Monatlich" : ""?>
|
||||
<?=($contract->billing_period == 12) ? "Jährlich" : ""?>
|
||||
<?=($contract->billing_period == 24) ? "Zweijährlich" : ""?>
|
||||
<?=($contract->billing_period == 36) ? "Dreijährlich" : ""?>
|
||||
</td>
|
||||
<th>Menge:</th>
|
||||
<td><?=(float)number_format($contract->amount, 3, ",", ".")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Preis Periodisch Netto:</th>
|
||||
<td class="<?=($contract->price < 0) ? "text-danger" : ""?>">€ <?=number_format(($contract->amount != 1) ? $contract->price * $contract->amount : $contract->price, 4, ",", ".")?></td>
|
||||
</tr><tr>
|
||||
<th>Preis Periodisch Brutto:</th>
|
||||
<td class="<?=($contract->price < 0) ? "text-danger" : ""?>">€
|
||||
<?php if($contract->price && $contract->vatrate): ?>
|
||||
<?php if($contract->amount != 1): ?>
|
||||
<?=number_format($contract->price + ($contract->price / 100) * $contract->vatrate, 4, ",", ".")?>
|
||||
<?php else: ?>
|
||||
<?=number_format(($contract->price + ($contract->price / 100) * $contract->vatrate) * $contract->amount, 4, ",", ".")?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<th>Verrechnungsperiode:</th>
|
||||
<td>
|
||||
<?=__($contract->billing_period, "billing_period")?>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<th>Herstellungskosten:</th>
|
||||
<td class="<?=($contract->price_setup < 0) ? "text-danger" : ""?>">
|
||||
<?php if($contract->price_setup > 0): ?>
|
||||
Netto: € <?=number_format($contract->price_setup, 4, ",", ".")?><?=($contract->amount != 1) ? " (Gesamt: € ".number_format($contract->price_setup * $contract->amount, 4, ",", ".").")" : ""?><br />
|
||||
Brutto: € <?=($contract->price_setup && $contract->vatrate) ? number_format($contract->price_setup + ($contract->price_setup / 100) * $contract->vatrate, 4, ",", ".") : ""?><?=($contract->price_setup && $contract->vatrate && $contract->amount != 1) ? " (Gesamt: € ".number_format(($contract->price_setup + ($contract->price_setup / 100) * $contract->vatrate) * $contract->amount, 4, ",", ".").")" : ""?></td>
|
||||
<?php endif; ?>
|
||||
</tr><tr>
|
||||
<th>Verrechnungsstart Verzögerung:</th>
|
||||
<td><?=$contract->billing_delay?> Monate</td>
|
||||
<td>
|
||||
<?php if($contract->billing_delay): ?>
|
||||
<?=$contract->billing_delay?> Monate
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<th></th>
|
||||
<td></td>
|
||||
@@ -205,14 +225,14 @@
|
||||
<td class="text-monospace"><?=date('d.m.Y H:i:s',$contract->edit)?> (<?=$contract->editor->name?>)</td>
|
||||
</tr><tr class="bg-white">
|
||||
<td colspan="2" class="text-center">
|
||||
<a href="<?=self::getUrl("Contractconfig", "edit", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-info">Konfiguration bearbeiten</button></a>
|
||||
<a href="<?=self::getUrl("Contractaccessletter", "view", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-success">Zugangsdaten anzeigen</button></a>
|
||||
<a href="<?=self::getUrl("Contractconfig", "edit", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-info"><i class="far fa-list-dropdown fa-fw"></i> Konfiguration bearbeiten</button></a>
|
||||
<a href="<?=self::getUrl("Contractaccessletter", "view", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-success"><i class="far fa-list-numeric fa-fw"></i> Zugangsdaten anzeigen</button></a>
|
||||
<?php if($contract->finish_date && $contract->finish_date < date('U')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary">Inhaberwechsel</button>
|
||||
<a href="<?=self::getUrl("Contract", "productchange", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-purple">Produkt-/Standortwechsel</button></a>
|
||||
<a href="<?=self::getUrl("Contract", "cancel", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-danger">Kündigen</button></a>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary"><i class="far fa-people-arrows fa-fw"></i> Inhaberwechsel</button>
|
||||
<a href="<?=self::getUrl("Contract", "productchange", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-purple"><i class="far fa-truck-container fa-fw"></i> Produkt-/Standortwechsel</button></a>
|
||||
<a href="<?=self::getUrl("Contract", "cancel", ["contract_id" => $contract->id])?>"><button type="button" class="btn btn-sm btn-outline-danger"><i class="far fa-axe fa-fw"></i> Kündigen</button></a>
|
||||
<?php else: ?>
|
||||
<a href="<?=self::getUrl("Contract", "finishContract", ['contract_id' => $contract->id])?>" onclick="if(!confirm('Jetzt fertigstellen und in Verrechnung geben?')) return false"><button type="button" class="btn btn-sm btn-success">Fertigstellen</button></a>
|
||||
<a href="<?=self::getUrl("Contract", "finishContract", ['contract_id' => $contract->id])?>" onclick="if(!confirm('Jetzt fertigstellen und in Verrechnung geben?')) return false"><button type="button" class="btn btn-sm btn-success"><i class="far fa-face-confused fa-fw"></i> Fertigstellen</button></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -276,6 +296,11 @@
|
||||
<em>Vertrag aus Bestellung <a href="<?=self::getUrl("Order", "edit", ["id" => $contract->orderproduct->order_id])?>">#<?=$contract->orderproduct->order_id?></a> erstellt
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php elseif($j->type == "contract_finished"): ?>
|
||||
<td><i class="fas fa-flag-checkered text-success pl-1"></i></td>
|
||||
<td style="width: 100%"><em>Vertag fertiggestellt</em>
|
||||
|
||||
</td>
|
||||
<?php elseif($j->type == "credit_created"): ?>
|
||||
<td><i class="far fa-money-bill-simple-wave text-secondary pl-1"></i></td>
|
||||
<td style="width: 100%"><em>Gutschrift-Vertrag <a href="<?=self::getUrl("Contract", "View", ["contract_id" => $j->value])?>"><?=$j->value?></a> erstellt</em>
|
||||
@@ -342,6 +367,8 @@
|
||||
<th>Kunde</th>
|
||||
<th>Contract ID</th>
|
||||
<th>Produkt</th>
|
||||
<th>Preis</th>
|
||||
<th>Preis Setup</th>
|
||||
<th>Bestelldatum</th>
|
||||
<th>Fertigstellung</th>
|
||||
<th>Kündigung</th>
|
||||
@@ -377,12 +404,14 @@
|
||||
<tr>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=__($link->type, "contract")?> <?=($link->type != "link") ? $direction : ""?></td>
|
||||
<td><a href="<?=self::getUrl("Address", "View", ["id" => $linkcontract->owner_id])?>"><?=$linkcontract->owner->getCompanyOrName()?></a></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>"><?=$linkcontract->id?></a></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?>"><a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>"><?=$linkcontract->id?></a></td>
|
||||
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>"><?=$linkcontract->product_name?> [<?=$linkcontract->matchcode?>]</a></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->order_date) ? date('d.m.Y', $linkcontract->order_date) : ""?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->finish_date) ? date('d.m.Y', $linkcontract->finish_date) : ""?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->cancel_date) ? date('d.m.Y', $linkcontract->cancel_date) : ""?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?>"><a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>"><?=$linkcontract->product_name?> [<?=$linkcontract->matchcode?>]</a></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : "" ?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?> <?=($linkcontract->price < 0) ? "text-danger" : ""?>">€ <?=number_format($linkcontract->price,4,",",".")?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : "" ?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?> <?=($linkcontract->price_setup < 0) ? "text-danger" : ""?>">€ <?=number_format($linkcontract->price_setup,4,",",".")?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?>"><?=($linkcontract->order_date) ? date('d.m.Y', $linkcontract->order_date) : ""?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?>"><?=($linkcontract->finish_date) ? date('d.m.Y', $linkcontract->finish_date) : ""?></td>
|
||||
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?> <?=(!$linkcontract->isFinished()) ? "not-finished" : "" ?>"><?=($linkcontract->cancel_date) ? date('d.m.Y', $linkcontract->cancel_date) : ""?></td>
|
||||
<td>
|
||||
<a href="<?=self::getUrl("Contract", "deleteLink", ["link_id" => $link->id])?>" onclick="if(!confirm('Verknüpfung wirklich entfernen?')) return false;" class="text-danger" title="Verknüpfung entfernen"><i class="fas fa-xmark-large"></i></a>
|
||||
</td>
|
||||
|
||||
1
Layout/default/Emailtemplates/Invoice/invoice.php
Normal file
1
Layout/default/Emailtemplates/Invoice/invoice.php
Normal file
@@ -0,0 +1 @@
|
||||
<?php
|
||||
128
Layout/default/Invoice/Index.php
Normal file
128
Layout/default/Invoice/Index.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
$pagination_baseurl = $this->getUrl($Mod, "Index");
|
||||
$pagination_baseurl_params = ["filter" => $filter];
|
||||
$pagination_entity_name = "Billingrecords";
|
||||
?>
|
||||
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
|
||||
|
||||
<!-- start page title -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="page-title-box">
|
||||
<div class="page-title-right">
|
||||
<ol class="breadcrumb m-0">
|
||||
<li class="breadcrumb-item"><a href="<?=self::getUrl("Dashboard")?>"><?=MFAPPNAME_SLUG?></a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">Rechnungen</li>
|
||||
</ol>
|
||||
</div>
|
||||
<h4 class="page-title">Rechnungen</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end page title -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body mb-3">
|
||||
<h4 class="header-title mb-3">Filter</h4>
|
||||
|
||||
<form method="get" action="<?=self::getUrl("Invoice")?>">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_customer_number">Kundennummer</label>
|
||||
<input type="text" class="form-control" name="filter[customer_number]" id="filter_customer_number" value="<?=(array_key_exists("customer_number", $filter)) ? $filter['customer_number'] : ""?>"/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_customer">Kunde</label>
|
||||
<input type="text" class="form-control" name="filter[customer]" id="filter_customer" value="<?=(array_key_exists("customer", $filter)) ? $filter['customer'] : ""?>"/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_address">Adresse</label>
|
||||
<input type="text" class="form-control" name="filter[address]" id="filter_address" value="<?=(array_key_exists("address", $filter)) ? $filter['address'] : ""?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary">Filter anwenden</button>
|
||||
<a class="btn btn-secondary" href="<?=self::getUrl("Invoice")?>?resetFilter=1">Filter zurücksetzen</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body mb-3">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="header-title">Rechnungen</h4>
|
||||
<!--button type="submit" class="btn btn-primary"><i class="fas fa-fw fa-check"></i> Markierte Elemente als Contract übernehmen</button-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
|
||||
|
||||
<table class="table table-sm table-striped table-hover">
|
||||
<tr>
|
||||
<th>Rechungsnummer</th>
|
||||
<th>Rechnungsdatum</th>
|
||||
<th>Kundennummer</th>
|
||||
<th>Rechnungsadresse</th>
|
||||
<th>Netto</th>
|
||||
<th>Ust.</th>
|
||||
<th>Brutto</th>
|
||||
<th>Zahlung</th>
|
||||
<th>Zustellung</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<?php foreach($invoices as $invoice): ?>
|
||||
<?php $total = $invoice->total + $invoice->total_setup; ?>
|
||||
<?php $total_gross = $invoice->total_gross + $invoice->total_setup_gross; ?>
|
||||
<tr>
|
||||
<td><a href="<?=self::getUrl("Invoice", "downloadInvoice", ["id" => $invoice->id])?>"><i class="fas fa-download fa-fw"></i> <?=$invoice->invoice_number?></a></td>
|
||||
<td><?=date("d.m.Y", $invoice->invoice_date)?></td>
|
||||
<td><?=$invoice->customer_number?></td>
|
||||
<td>
|
||||
<?=($invoice->company) ? $invoice->company."<br />" : ""?>
|
||||
<?=($invoice->firstname || $invoice->lastname) ? $invoice->firstname." ".$invoice->lastname."<br />" : ""?>
|
||||
<?=$invoice->street?><br />
|
||||
<?=$invoice->zip?> <?=$invoice->city?><br />
|
||||
<?=$invoice->country?>
|
||||
</td>
|
||||
<td class="<?=($total < 0) ? "text-danger" : ""?>">€ <?=number_format($total,2,",",".")?></td>
|
||||
<td class="<?=($invoice->total_vat < 0) ? "text-danger" : ""?>">€ <?=number_format($invoice->total_vat,2,",",".")?></td>
|
||||
<td class="<?=($total_gross < 0) ? "text-danger" : ""?>">€ <?=number_format($total_gross,2,",",".")?></td>
|
||||
<td><?=($invoice->billing_type == "sepa") ? "SEPA" : "Überweisung"?></td>
|
||||
<td><?=($invoice->billing_delivery == "email") ? "Email" : "Papier"?></td>
|
||||
<td><a href="<?=self::getUrl("Invoice", "downloadInvoice", ["id" => $invoice->id])?>"><i class="fas fa-download fa-fw"></i></a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>
|
||||
158
Layout/default/Invoice/Print.pdf.php
Normal file
158
Layout/default/Invoice/Print.pdf.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* @var string $ressourcePathPrefix
|
||||
* @var Invoice $invoice
|
||||
* @var float $vat
|
||||
*/
|
||||
$net_total = $invoice->total + $invoice->total_setup;
|
||||
$gross_total = $invoice->total_gross + $invoice->total_setup_gross;
|
||||
$is_credit = $net_total < 0;
|
||||
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Xinon Billing - Rechnung <?=$invoice->invoice_number?></title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
||||
<link href="<?=$ressourcePathPrefix?>css/sknx_print.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table id="adressen">
|
||||
<tr>
|
||||
<td class="left">
|
||||
|
||||
<div class="adresse">
|
||||
<div><?=$invoice->company?><br />
|
||||
<?php if($invoice->firstname && $invoice->lastname): ?><?=$invoice->firstname?> <?=$invoice->lastname?><br /><?php endif; ?>
|
||||
<?=nl2br($invoice->street)?><br />
|
||||
<?=$invoice->zip?> <?=$invoice->city?><br />
|
||||
<?php if($invoice->country != "Österreich"):?><?=$invoice->country?><br /><?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div style="height:40pt;"></div>
|
||||
<h2><?php if($is_credit):?>Gutschrift<?php else: ?>Rechnung<?php endif; ?> <?=$invoice->invoice_number?></h2>
|
||||
<div><b><?php if($is_credit):?>Belegdatum<?php else: ?>Rechnungsdatum<?php endif; ?>: <?=date("d.m.Y",$invoice->invoice_date)?></b>
|
||||
<?php if($invoice->uid): ?><br />Ihre UID: <?=$invoice->uid?><?php endif; ?>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
<td class="right">
|
||||
|
||||
<div class="adresse header_sknx">
|
||||
<div>
|
||||
<div><img src="<?=$ressourcePathPrefix?>assets/images/xinon-dark.png" style="width:100%;" /></div>
|
||||
<div><b>Xinon GmbH</b></div>
|
||||
<div>Fladnitz im Raabtal 150<br />
|
||||
A-8322 Studenzen<br />
|
||||
<br />
|
||||
Tel +43 3115 40800<br />
|
||||
office@xinon.at - https://xinon.at/<br />
|
||||
UID: ATU68711968<br />
|
||||
FB: FN 416556 h<br />
|
||||
<br />
|
||||
Bankverbindung:<br />
|
||||
Steiermärkische Bank und Sparkassen AG<br />
|
||||
BIC: STSPAT2GXXX<br />
|
||||
IBAN: AT84 2081 5000 4007 9121
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<div style="height:28pt;"></div>
|
||||
|
||||
<div id="rechnungspositionen">
|
||||
|
||||
<?php if(is_array($invoice->positions) && count($invoice->positions)): ?>
|
||||
|
||||
<table class="position">
|
||||
<tr class="head dontsplit">
|
||||
<th class="name">Bezeichnung</th>
|
||||
<th class="preis">Einzelpreis</th>
|
||||
<th class="menge">Menge</th>
|
||||
<th class="preis">Gesamtpreis</th>
|
||||
<th class="preis">Ust.</th>
|
||||
<th class="preis">Gesamt Brutto</th>
|
||||
</tr>
|
||||
<?php $i=0; ?>
|
||||
<?php foreach($invoice->positions as $p): ?>
|
||||
<?php
|
||||
$start_date = new DateTime($p->start_date);
|
||||
$end_date = new DateTime($p->end_date);
|
||||
$amount = (float) number_format($p->amount, 3, ",", ".");
|
||||
$price = number_format($p->price, 2, ",",".");
|
||||
$price_total = number_format($p->price_total, 2, ",",".");
|
||||
$price_gross = number_format($p->price_gross, 2, ",",".");
|
||||
$vatrate = number_format($p->vatrate, 2, ",",".");
|
||||
?>
|
||||
<tr class="<?=($i%2 == 0) ? "even" : "odd" ?> one-position">
|
||||
<td class="name">
|
||||
<span class="product-name"><?=$p->product_name?></span>
|
||||
<?php if($start_date->format("d.m.Y") != $end_date->format("d.m.Y")): ?>
|
||||
(<?=$start_date->format("d.m.Y")?> - <?=$end_date->format("d.m.Y")?>)
|
||||
<?php endif; ?>
|
||||
<?=($p->matchcode) ? "<div class='pl-2'>".$p->matchcode."</div>" : ""?>
|
||||
<?=($p->product_info) ? "<div class='pl-2'>".nl2br($p->product_info)."</div>" : ""?>
|
||||
</td>
|
||||
<td class="preis"><?=$price?> €</td>
|
||||
<td class="preis"><?=$amount?></td>
|
||||
<td class="preis"><?=$price_total?> €</td>
|
||||
<td class="preis"><?=$vatrate?>%</td>
|
||||
<td class="preis"><?=$price_gross?> €</td>
|
||||
</tr>
|
||||
|
||||
<?php $i++; ?>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="height:40pt;"></div>
|
||||
|
||||
<table id="total">
|
||||
<?php if(!$reversecharge): ?>
|
||||
<tr class="netto">
|
||||
<th>Gesamtbetrag Netto:</th>
|
||||
<td><?=number_format($net_total, 2, ",", ".")?> €</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<?php foreach($vat as $vatrate => $vat_total): ?>
|
||||
<?php if($vat_total != 0 && $vatrate > 0): ?>
|
||||
<tr class="ust">
|
||||
<th>+ Umsatzsteuer <?=$vatrate?>%:</th>
|
||||
<td><?=number_format($vat_total, 2, ",", ".")?> €</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
<tr class="brutto">
|
||||
<?php if($reversecharge): ?>
|
||||
<th>Gesamtbetrag:</th>
|
||||
<?php else: ?>
|
||||
<th>Gesamtbetrag Brutto:</th>
|
||||
<?php endif; ?>
|
||||
<td><?=number_format($gross_total, 2, ",", ".")?> €</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
<?php if($reversecharge): ?>
|
||||
<p style="font-weight:bold;">Hinweis: Die Umsatzsteuerschuld geht auf den Leistungsempfänger über (Reverse Charge)</p>
|
||||
<?php endif; ?>
|
||||
<?php if($is_credit): ?>
|
||||
<p>Gutschrift! Bitte nicht überweisen.</p>
|
||||
<?php else: ?>
|
||||
Ohne Abzug zu bezahlen bis <?=(new DateTime("@".$invoice->invoice_date))->modify("+14 days")->format("d.m.Y")?>.<br />
|
||||
Bitte geben Sie als Verwendungszweck unbedingt die Rechnungsnummer an, nur so können wir Ihre Zahlung eindeutig zuordnen
|
||||
<?php endif; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -218,6 +218,12 @@
|
||||
<label for="can_order" class="form-check-label">Bestellung</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="form-group form-check">
|
||||
<input type="checkbox" class="form-check-input" name="can[Billing]" id="can_billing" value="1" <?=$user && $user->can("Billing") ? "checked='checked'" : ""?> />
|
||||
<label for="can_billing" class="form-check-label">Verrechnung</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="card-title mb-3 mt-3">Zusatzberechtigungen</h4>
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<li ><a href="<?=self::getUrl("Devicemanufactor")?>"><i class="fad fa-fw fa-router text-info"></i> Geräte Hersteller</a></li>
|
||||
<li><a href="<?=self::getUrl("Devicetype")?>"><i class="fad fa-fw fa-router text-info"></i> Geräte Typen</a></li>
|
||||
<li class="has-sub-submenu"><a href="<?=self::getUrl("Device")?>"><i class="fad fa-fw fa-router text-info "></i> Devices</a></li>
|
||||
<li class="has-sub-submenu"><a href="<?=self::getUrl("User")?>"><i class="fad fa-fw fa-users text-info"></i> Benutzer</a></li>
|
||||
<li class="has-sub-submenu"><a href="<?=self::getUrl("User")?>"><i class="fad fa-fw fa-users text-info"></i> Benutzer</a></li>
|
||||
<li class="has-sub-submenu font-weight-bold mt-1 mobile-hide"><a>Grundstammdaten</a></li>
|
||||
<?php endif; ?>
|
||||
<?php if($me->is(["Admin"]) || ($me->is("netowner") && $me->hasGwrNetworks())): ?>
|
||||
@@ -86,6 +86,18 @@
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($me->is(["Admin"])): ?>
|
||||
<li class="has-submenu mobile-hide">
|
||||
<a href="#">
|
||||
<i class="fas fa-fw fa-money-from-bracket"></i>Verrechnung <div class="arrow-down"></div>
|
||||
</a>
|
||||
<ul class="submenu">
|
||||
<li><a href="<?=self::getUrl("Contract")?>"><i class="far fa-fw fa-id-card text-info"></i> Contracts</a></li>
|
||||
<li class="has-sub-submenu"><a href="<?=self::getUrl("Contract", "AdvancedSearch")?>"><i class="far fa-fw fa-question-circle text-info"></i> Erweiterte Suche</a></li>
|
||||
<?php if($me->is(["Admin"]) && $me->can("Billing")): ?><li><a href="<?=self::getUrl("Billing")?>"><i class="far fa-fw fa-cash-register text-info"></i> Verrechnung</a></li><?php endif; ?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($me->is(["Admin","netowner","lineplanner","pipeplanner","pipeworker","lineworker"])): ?>
|
||||
<li class="has-submenu mobile-hide">
|
||||
|
||||
@@ -199,11 +199,11 @@ class Admin_IvtContractImport {
|
||||
switch($ip->interval) {
|
||||
case 0:
|
||||
$contract_data['billing_period'] = 1;
|
||||
$finish_date->modify("+1 month");
|
||||
//$finish_date->modify("+1 month");
|
||||
break;
|
||||
case 1:
|
||||
$contract_data['billing_period'] = 12;
|
||||
$finish_date->modify("+1 year");
|
||||
//$finish_date->modify("+1 year");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ class Admin_IvtContractImport {
|
||||
$contract = ContractModel::create($contract_data);
|
||||
if(trim($ivt_contract->comment)) {
|
||||
$contract->matchcode = trim($ivt_contract->comment);
|
||||
} else {
|
||||
} elseif(!in_array($ivt_contract->id, $this->no_matchcode)) {
|
||||
$contract->matchcode = $contract->generateMatchcode();
|
||||
}
|
||||
/*if($ivt_contract->id == 3035) {
|
||||
@@ -336,8 +336,6 @@ class Admin_IvtContractImport {
|
||||
foreach($new_contracts as $ivt_customer_id => $contracts) {
|
||||
$this->addVoipData($ivt_customer_id, $contracts);
|
||||
|
||||
if(in_array($ivt_contract->id, $this->no_matchcode)) break;
|
||||
|
||||
if(count($contracts) < 2) continue;
|
||||
$prev_contracts = [];
|
||||
$primary_matchcode = false;
|
||||
@@ -347,10 +345,12 @@ class Admin_IvtContractImport {
|
||||
|
||||
foreach($contracts as $contract) {
|
||||
if($contract->matchcode && !$primary_matchcode && !preg_match($primary_matchcode_no_productgroups_pattern, $contract->product->productgroup->name)) {
|
||||
if(in_array($ivt_contract->id, $this->no_matchcode)) continue;
|
||||
$primary_matchcode = $contract->matchcode;
|
||||
$primary_matchcode_source_product_group = $contract->product->productgroup->name;
|
||||
}
|
||||
if($primary_matchcode && !$contract->matchcode && !preg_match($primary_matchcode_no_productgroups_pattern, $primary_matchcode_source_product_group)) {
|
||||
if(in_array($ivt_contract->id, $this->no_matchcode)) continue;
|
||||
$contract->matchcode = $primary_matchcode;
|
||||
$contract->save();
|
||||
}
|
||||
|
||||
@@ -66,6 +66,22 @@ class BillingController extends mfBaseController {
|
||||
$new_filter["price>="] = 0;
|
||||
}
|
||||
|
||||
if(array_key_exists("customer", $filter)) {
|
||||
if(array_key_exists("customer", $filter) && $filter["customer"]) {
|
||||
$kunde = $this->db()->escape($filter['customer']);
|
||||
if(!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = "";
|
||||
$new_filter['add-where'] .= " AND (company like '%$kunde%' OR firstname like '%$kunde%' OR lastname like '%$kunde%' OR concat(firstname, ' ', lastname) like '%$kunde%' OR concat(lastname, ' ', firstname) like '%$kunde%')";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("address", $filter)) {
|
||||
if(array_key_exists("address", $filter) && $filter["address"]) {
|
||||
$search = $this->db()->escape($filter['address']);
|
||||
if(!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = "";
|
||||
$new_filter['add-where'] .= " AND (street like '%$search%' OR zip like '%$search%' OR city like '%$search%' OR country like '%$search%')";
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($filter) && count($filter)) {
|
||||
foreach ($filter as $name => $value) {
|
||||
$new_filter[$name] = $value;
|
||||
@@ -86,19 +102,33 @@ class BillingController extends mfBaseController {
|
||||
|
||||
$i = 0;
|
||||
|
||||
//$yearly_not_before = new DateTime("2023-06-01");
|
||||
|
||||
$now_year = date("Y");
|
||||
$now_month = date("m");
|
||||
$now_day = date("d");
|
||||
$now_year = 2024;
|
||||
$now_month = 7;
|
||||
|
||||
// XXX only for 1st Billing after IVT Import
|
||||
//$yearly_not_before = new DateTime("$now_year-$now_month-01");
|
||||
$yearly_not_before = new DateTime("$now_year-06-01");
|
||||
|
||||
$del = 0;
|
||||
// first delete all non-invoiced billing records
|
||||
/*foreach(BillingModel::search(["invoice_id" => null]) as $bill) {
|
||||
$bill->delete();
|
||||
$del++;
|
||||
}*/
|
||||
|
||||
$this->log->notice(__METHOD__.": $del Billing records deleted");
|
||||
//$stop = false;
|
||||
foreach(ContractModel::search(["finish_date<" => mktime(0,0,0,$now_month, $now_day, $now_year), "cancel_date" => null]) as $contract) {
|
||||
//while(!$stop) {
|
||||
//$stop = true;
|
||||
//$contract = new Contract(1475);
|
||||
|
||||
//var_dump($contract);exit;
|
||||
//$contract = new Contract(1);
|
||||
|
||||
|
||||
|
||||
|
||||
$bill_month = $now_month;
|
||||
$bill_year = $now_year;
|
||||
//$bill_day = $now_day;
|
||||
@@ -108,22 +138,27 @@ class BillingController extends mfBaseController {
|
||||
$monthly_bill_period_to->modify("last day of this month");
|
||||
|
||||
$contract_finish_date = new DateTime("@".$contract->finish_date);
|
||||
$finish_year = date("Y", $contract->finish_date);
|
||||
$finish_month = date("m", $contract->finish_date);
|
||||
$finish_day = date("d", $contract->finish_date);
|
||||
$contract_finish_date->setTimezone(new DateTimeZone("Europe/Vienna"));
|
||||
$contract_finish_date->setTime(0,0,0);
|
||||
if($contract->billing_delay) {
|
||||
// add billing delay to finish_date so the first x months won't be billed
|
||||
$this->log->debug(__METHOD__.": Adding ".$contract->billing_delay." billing_delay months to finish_date");
|
||||
$contract_finish_date->modify("+".$contract->billing_delay." months");
|
||||
}
|
||||
|
||||
//echo "$bill_month $bill_year\n";exit;
|
||||
$finish_year = $contract_finish_date->format("Y");
|
||||
$finish_month = $contract_finish_date->format("m");
|
||||
$finish_day = $contract_finish_date->format("d");
|
||||
|
||||
//echo $monthly_bill_period_to->format("Y-m-d H:i:s");exit;
|
||||
if($contract_finish_date > $monthly_bill_period_to) {
|
||||
$this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." because finish_date is in $finish_month $finish_year");
|
||||
continue;
|
||||
}
|
||||
|
||||
if($contract->billing_period < 1) {
|
||||
/*if($contract->billing_period < 1) {
|
||||
$this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." because billing_period == 0");
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
if($contract->price == 0 && $contract->price_setup == 0) {
|
||||
$this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." because price and price_setup == 0");
|
||||
continue;
|
||||
@@ -138,177 +173,156 @@ class BillingController extends mfBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
$start_date = new DateTime("@".$contract->finish_date);
|
||||
$start_date->setTimezone(new DateTimeZone("Europe/Vienna"));
|
||||
//$start_date = clone $contract_finish_date;
|
||||
|
||||
// ignore yearly contracts which are not billable this month
|
||||
if($contract->billing_period == 12) {
|
||||
if($start_date->format("m") != $bill_month) {
|
||||
/*if($contract->billing_period == 12) {
|
||||
if($contract_finish_date->format("m") != $bill_month) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
$create_bills = [];
|
||||
|
||||
// Concurrent Billing
|
||||
// find not yet billed periods
|
||||
|
||||
$create_dates = [];
|
||||
|
||||
$create_date = clone $start_date;
|
||||
//$create_date->modify("+".$contract->billing_period." month");
|
||||
$create_date->modify("first day of this month");
|
||||
$last_create_date = false;
|
||||
//echo "first create_date: ".$create_date->format("Y-m-d H:i:s")."<br />\n";
|
||||
//echo "while ".$create_date->getTimestamp()." (".$create_date->format("Y-m-d H:i:s").") >= ".$contract->finish_date." (".date("Y-m-d H:i:s", $contract->finish_date).")<br>\n";
|
||||
|
||||
while($create_date->getTimestamp() >= $contract->finish_date) {
|
||||
//echo "in need date while (".$create_date->format("Y-m-d H:i:s").")<br>";
|
||||
if($last_create_date) {
|
||||
// must for safety / shouldn't happen
|
||||
die("need-date ran out of dates");
|
||||
}
|
||||
|
||||
//echo " ";
|
||||
//echo $create_date->format("Y")." == ".$finish_year." && ".$create_date->format("m")." == ".$finish_month."<br>";
|
||||
if($create_date->format("Y") == $finish_year && $create_date->format("m") == $finish_month) {
|
||||
$create_date->setDate($finish_year, $finish_month, $finish_day);
|
||||
//echo "set last_create_date true<br>";
|
||||
$last_create_date = true;
|
||||
}
|
||||
|
||||
$existing_bill = BillingModel::getFirst(["contract_id" => $contract->id, "start_date" => $create_date->format("Y-m-d")]);
|
||||
//var_dump($need_bill);exit;
|
||||
if(!$existing_bill) {
|
||||
//echo "adding date to create_dates[]<br>";
|
||||
$new_create_date = clone $create_date;
|
||||
$create_dates[] = $new_create_date;
|
||||
$create_date->modify("-".$contract->billing_period." months");
|
||||
if(!$contract->billing_period) {
|
||||
// setup only
|
||||
if(BillingModel::getFirst(["contract_id" => $contract->id])) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//var_dump($create_dates);
|
||||
// find missing billings
|
||||
foreach($create_dates as $start_date) {
|
||||
$price_setup = 0;
|
||||
if($start_date->format("Y") == $finish_year && $start_date->format("m") == $finish_month) {
|
||||
$price_setup = $contract->price_setup;
|
||||
}
|
||||
$create_bills[] = [
|
||||
"start_date" => $start_date,
|
||||
"price_setup" => $price_setup // set Setup price to 0, because it was billed already
|
||||
];
|
||||
}
|
||||
|
||||
/*$last_billings = BillingModel::count(["contract_id" => $contract->id]);
|
||||
if(!$last_billings) {
|
||||
// First billing
|
||||
$start_date->setTime(0,0,0);
|
||||
//echo "start_date: ".$start_date->format("Y-m-d H:i:s")."<br />";
|
||||
$create_bills[] = [
|
||||
"start_date" => $start_date,
|
||||
"start_date" => $contract_finish_date,
|
||||
"end_date" => $contract_finish_date,
|
||||
"price_setup" => $contract->price_setup
|
||||
];
|
||||
} else {
|
||||
// Concurrent Billing
|
||||
// find not yet billed periods
|
||||
|
||||
// contracts with billing period
|
||||
$create_dates = [];
|
||||
|
||||
$create_date = clone $start_date;
|
||||
$create_date->modify("+1 month");
|
||||
$create_date->modify("first day of this month");
|
||||
$last_create_date = false;
|
||||
//echo "first create_date: ".$create_date->format("Y-m-d H:i:s")."<br />\n";
|
||||
//echo "while ".$create_date->getTimestamp()." (".$create_date->format("Y-m-d H:i:s").") >= ".$contract->finish_date." (".date("Y-m-d H:i:s", $contract->finish_date).")<br>\n";
|
||||
//echo "initial bill_date: ".$bill_date->format("Y-m-d")."<br>";
|
||||
|
||||
while($create_date->getTimestamp() >= $contract->finish_date) {
|
||||
//echo "in need date while (".$create_date->format("Y-m-d H:i:s").")<br>";
|
||||
// if more than 1 month period, adjust initial billing_date to contracts finish_date in current period
|
||||
// otherwise i.e. yearly contracts older than one year would never be billed ever, or in the best case
|
||||
// they would be billed a few months too late
|
||||
if($contract->billing_period > 1 && $bill_date > $contract_finish_date) {
|
||||
$new_bill_date = clone $contract_finish_date;
|
||||
$new_bill_date->modify("+".$contract->billing_period." months");
|
||||
|
||||
while($new_bill_date->format("Ymd") < $bill_date->format("Ymd")) {
|
||||
$new_bill_date->modify("+".$contract->billing_period." months");
|
||||
}
|
||||
|
||||
if($new_bill_date->format("Ymd") > $bill_date->format("Ymd")) {
|
||||
$new_bill_date->modify("-".$contract->billing_period." months");
|
||||
}
|
||||
|
||||
$bill_date = $new_bill_date;
|
||||
//echo "new bill_date: ".$bill_date->format("Y-m-d");
|
||||
}
|
||||
$create_date = clone $bill_date;
|
||||
$create_date->modify("first day of this month");
|
||||
$create_date->setTime(0,0,0);
|
||||
$last_create_date = false;
|
||||
|
||||
$earliest_bill_date = clone $contract_finish_date;
|
||||
$earliest_bill_date->modify("first day of this month");
|
||||
$earliest_bill_date->setTime(0,0,0);
|
||||
|
||||
while($create_date->format("Y-m-d") >= $earliest_bill_date->format("Y-m-d")) {
|
||||
if($last_create_date) {
|
||||
// must for safety / shouldn't happen
|
||||
// just for safety / shouldn't happen
|
||||
die("need-date ran out of dates");
|
||||
}
|
||||
|
||||
//echo " ";
|
||||
//echo $create_date->format("Y")." == ".$finish_year." && ".$create_date->format("m")." == ".$finish_month."<br>";
|
||||
if($create_date->format("Y") == $finish_year && $create_date->format("m") == $finish_month) {
|
||||
// this is the finish month, so set day back to day of finish_date
|
||||
$create_date->setDate($finish_year, $finish_month, $finish_day);
|
||||
//echo "set last_create_date true<br>";
|
||||
$last_create_date = true;
|
||||
}
|
||||
|
||||
$existing_bill = BillingModel::getFirst(["contract_id" => $contract->id, "start_date" => $create_date->format("Y-m-d")]);
|
||||
//var_dump($need_bill);exit;
|
||||
if(!$existing_bill) {
|
||||
//echo "adding date to create_dates[]<br>";
|
||||
$new_create_date = clone $create_date;
|
||||
$create_dates[] = $new_create_date;
|
||||
$create_date->modify("-".$contract->billing_period." months");
|
||||
$create_date->modify("-" . $contract->billing_period . " months");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//var_dump($create_dates);
|
||||
// find missing billings
|
||||
foreach($create_dates as $start_date) {
|
||||
// ignore if last billing row is from this month
|
||||
/*if($start_date->getTimestamp() < $earliest_next_billing_date->getTimestamp()) {
|
||||
$this->log->debug(__METHOD__.": last billing row is current billing row. Skip creating new billing row");
|
||||
continue;
|
||||
}*//*
|
||||
$price_setup = 0;
|
||||
if($start_date->format("Y") == $finish_year && $start_date->format("m") == $finish_month) {
|
||||
$price_setup = $contract->price_setup;
|
||||
}
|
||||
$create_bills[] = [
|
||||
"start_date" => $start_date,
|
||||
"price_setup" => 0 // set Setup price to 0, because it was billed already
|
||||
"price_setup" => $price_setup // set Setup price to 0, because it was billed already
|
||||
];
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
$create_bills = array_reverse($create_bills);
|
||||
//var_dump($create_bills);exit;
|
||||
foreach($create_bills as $bill_data) {
|
||||
$start_date = $bill_data["start_date"];
|
||||
$end_date = (array_key_exists("end_date", $bill_data)) ? $bill_data["end_date"] : null;
|
||||
$price_setup = $bill_data["price_setup"];
|
||||
|
||||
if($contract->billing_period > 1 && $start_date < $yearly_not_before) {
|
||||
// XXX only for 1st Billing after IVT Import
|
||||
$this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." with start_date ".$start_date->format("Y-m-d")." because is yearly and before ".$yearly_not_before->format("Y-m-d"));
|
||||
continue;
|
||||
}
|
||||
|
||||
// if contract has cancel date this month
|
||||
// use cancel date as end_date
|
||||
if ($cancel_date) {
|
||||
$end_date = clone $cancel_date;
|
||||
} else {
|
||||
} elseif(!$end_date) {
|
||||
// else calculate last of month
|
||||
$end_date = clone $start_date;
|
||||
$end_date->modify("first day of this month");
|
||||
$end_date->modify("+" . $contract->billing_period . " months");
|
||||
//$end_date->modify("first day of this month");
|
||||
$end_date->modify("-1 day");
|
||||
}
|
||||
|
||||
|
||||
|
||||
$sday = $start_date->format("d");
|
||||
$eday = $end_date->format("d");
|
||||
|
||||
if ($sday > 1 || $cancel_date) {
|
||||
if ($contract->price && ($sday > 1 || $cancel_date)) {
|
||||
// aliquoter preis
|
||||
$days = ($eday - $sday) + 1;
|
||||
//echo "days: $days<br />";
|
||||
$pc = $days / $eday * 100;
|
||||
//echo "pc: $pc<br />";
|
||||
|
||||
$first_of_period = clone $start_date;
|
||||
$first_of_period->modify("first day of this month");
|
||||
|
||||
$total_days = $end_date->diff($first_of_period)->format("%a") + 1;
|
||||
$period_days = ($end_date->diff($start_date)->format("%a")) + 1;
|
||||
|
||||
$pc = $period_days / $total_days * 100;
|
||||
$price = round($contract->price / 100 * $pc, 4);
|
||||
|
||||
/*if($contract->id == 8766) {
|
||||
echo "start date: ".$start_date->format("Y-m-d H:i:s") . "<br>";
|
||||
echo "end date: ".$end_date->format("Y-m-d H:i:s") . "<br><br>";
|
||||
echo "first_of_period: " . $first_of_period->format("Y-m-d H:i:s") . "<br>";
|
||||
echo "total days: $total_days<br>";
|
||||
echo "period days: $period_days<br>";
|
||||
echo "price: $price<br><br>";
|
||||
echo "classic days: $days<br>";
|
||||
exit;
|
||||
}*/
|
||||
} else {
|
||||
$price = $contract->price;
|
||||
}
|
||||
|
||||
/*
|
||||
echo "contact ID: ".$contract->id."<br />";
|
||||
echo "contract price: ". $contract->price."<br />";
|
||||
echo "price: ". $price."<br />";
|
||||
echo "start_date: ".$start_date->format("Y-m-d H:i:s")."<br />";
|
||||
echo "sday: $sday<br />";
|
||||
exit;
|
||||
*/
|
||||
|
||||
|
||||
$owner = $contract->owner;
|
||||
$billingaddress = $contract->billingaddress;
|
||||
@@ -334,6 +348,7 @@ class BillingController extends mfBaseController {
|
||||
$data["contract_id"] = $contract->id;
|
||||
$data["start_date"] = $start_date->format("Y-m-d");
|
||||
$data["end_date"] = $end_date->format("Y-m-d");
|
||||
$data["owner_id"] = $contract->owner_id;
|
||||
$data["billingaddress_id"] = ($contract->billingaddress_id) ? $contract->billingaddress_id : $contract->owner_id;
|
||||
$data["customer_number"] = $contract->owner->customer_number;
|
||||
$data["company"] = $billingaddress->company;
|
||||
@@ -351,13 +366,14 @@ class BillingController extends mfBaseController {
|
||||
$data["bank_account_owner"] = $billingaddress->bank_account_owner;
|
||||
$data["bank_account_iban"] = $billingaddress->bank_account_iban;
|
||||
$data["bank_account_bic"] = $billingaddress->bank_account_bic;
|
||||
$data["matchcode"] = $contract->mathcode;
|
||||
$data["matchcode"] = $contract->matchcode;
|
||||
$data["product_id"] = $contract->product_id;
|
||||
$data["product_name"] = $contract->product_name;
|
||||
$data["product_info"] = $contract->product_info;
|
||||
$data["amount"] = $contract->amount;
|
||||
$data["price"] = $price;
|
||||
$data["price_setup"] = $price_setup;
|
||||
$data["vatrate"] = $contract->vatrate;
|
||||
$data["billing_period"] = $contract->billing_period;
|
||||
|
||||
$billing = BillingModel::create($data);
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
class BillingModel {
|
||||
public $invoice_id;
|
||||
public $invoice_date;
|
||||
public $contract_id;
|
||||
public $start_date;
|
||||
public $end_date;
|
||||
public $owner_id;
|
||||
public $billingaddress_id;
|
||||
public $customer_number;
|
||||
public $company;
|
||||
@@ -30,8 +30,8 @@ class BillingModel {
|
||||
public $amount;
|
||||
public $price;
|
||||
public $price_setup;
|
||||
public $billing_period;
|
||||
|
||||
public $vatrate;
|
||||
|
||||
public $create_by;
|
||||
public $edit_by;
|
||||
public $create;
|
||||
@@ -117,6 +117,31 @@ class BillingModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getInvoiceBaseData($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$items = [];
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT owner_id, billingaddress_id, billing_type, billing_delivery FROM Billing
|
||||
WHERE $where
|
||||
GROUP BY owner_id, billingaddress_id, billing_type, billing_delivery
|
||||
ORDER BY owner_id, billingaddress_id, billing_type, billing_delivery";
|
||||
//var_dump($sql);exit;
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
while($data = $db->fetch_object($res)) {
|
||||
$items[] = [
|
||||
"owner_id" => $data->owner_id,
|
||||
"billingaddress_id" => $data->billingaddress_id,
|
||||
"billing_type" => $data->billing_type,
|
||||
"billing_delivery" => $data->billing_delivery
|
||||
];
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
public static function count($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
@@ -196,16 +221,11 @@ class BillingModel {
|
||||
$invoice_id = $filter['invoice_id'];
|
||||
if(is_numeric($invoice_id)) {
|
||||
$where .= " AND Billing.invoice_id=$invoice_id";
|
||||
} elseif($invoice_id === null || $invoice_id === false) {
|
||||
$where .= " AND (Billing.invoice_id IS NULL OR Billing.invoice_id=0)";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("invoice_date", $filter)) {
|
||||
$invoice_date = $filter['invoice_date'];
|
||||
if($invoice_date) {
|
||||
$where .= " AND Billing.invoice_date='$invoice_date'";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("contract_id", $filter)) {
|
||||
$contract_id = $filter['contract_id'];
|
||||
if(is_numeric($contract_id)) {
|
||||
@@ -237,7 +257,7 @@ class BillingModel {
|
||||
if(array_key_exists("start_date>=", $filter)) {
|
||||
$start_date = FronkDB::singleton()->escape($filter['start_date>=']);
|
||||
if($start_date) {
|
||||
$where .= " AND Billing.start_date >='$start_date'";
|
||||
$where .= " AND Billing.start_date >= '$start_date'";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,6 +268,13 @@ class BillingModel {
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("owner_id", $filter)) {
|
||||
$owner_id = $filter['owner_id'];
|
||||
if(is_numeric($owner_id)) {
|
||||
$where .= " AND Billing.owner_id=$owner_id";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("billingaddress_id", $filter)) {
|
||||
$billingaddress_id = $filter['billingaddress_id'];
|
||||
if(is_numeric($billingaddress_id)) {
|
||||
@@ -384,10 +411,24 @@ class BillingModel {
|
||||
}
|
||||
|
||||
|
||||
if(array_key_exists("billing_period", $filter)) {
|
||||
$billing_period = $filter['billing_period'];
|
||||
if(is_numeric($billing_period)) {
|
||||
$where .= " AND Billing.billing_period = $billing_period";
|
||||
if(array_key_exists("billing_type", $filter)) {
|
||||
$billing_type = $filter['billing_type'];
|
||||
if(is_numeric($billing_type)) {
|
||||
$where .= " AND Billing.billing_type = $billing_type";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("billing_type", $filter)) {
|
||||
$billing_type = $db->escape($filter['billing_type']);
|
||||
if($billing_type) {
|
||||
$where .= " AND Billing.billing_type = '$billing_type'";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("billing_delivery", $filter)) {
|
||||
$billing_delivery = $db->escape($filter['billing_delivery']);
|
||||
if($billing_delivery) {
|
||||
$where .= " AND Billing.billing_delivery = '$billing_delivery'";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class Contract extends mfBaseModel {
|
||||
private $creator;
|
||||
private $editor;
|
||||
|
||||
|
||||
|
||||
private function getLinks() {
|
||||
$this->linkFrom = [];
|
||||
$this->linkTo = [];
|
||||
|
||||
@@ -350,9 +350,6 @@ class ContractController extends mfBaseController
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: alten Credit Vertag kündigen und neuen anlegen
|
||||
*/
|
||||
foreach (ContractLinkModel::search(['type' => "credit", 'contract_id' => $origin->id]) as $old_credit) {
|
||||
// verlinkten Contract kündigen (wenn nicht schon gekündigt)
|
||||
if ($old_credit->change_action == "recreate" && !$old_credit->contract->cancel_date) {
|
||||
@@ -368,7 +365,6 @@ class ContractController extends mfBaseController
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -379,9 +375,12 @@ class ContractController extends mfBaseController
|
||||
$this->redirect("Contract", "view", ['contract_id' => $id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* bestehende Links übernehmen oder kündigen
|
||||
*/
|
||||
// create Journal
|
||||
$journal = ContractjournalModel::create([
|
||||
'contract_id' => $contract->id,
|
||||
'type' => "contract_finished"
|
||||
]);
|
||||
$journal_id = $journal->save();
|
||||
|
||||
$this->layout()->setFlash("Contract erfolgreich fertiggestellt", "success");
|
||||
$this->redirect("Contract", "view", ['contract_id' => $id]);
|
||||
@@ -475,6 +474,8 @@ class ContractController extends mfBaseController
|
||||
}
|
||||
|
||||
//var_dump($r->get());exit;
|
||||
|
||||
|
||||
$contract_data = [];
|
||||
$contract_data["owner_id"] = (int)$r->owner_id;
|
||||
$contract_data["billingaddress_id"] = ($r->billingaddress_id) ? (int)$r->billingaddress_id : null;
|
||||
@@ -489,11 +490,34 @@ class ContractController extends mfBaseController
|
||||
$contract_data['price_nbe'] = (float)$r->price_nbe;
|
||||
$contract_data['billing_period'] = (int)$r->billing_period;
|
||||
$contract_data['billing_delay'] = (int)$r->billing_delay;
|
||||
$contract_data['order_date'] = ($r->order_date) ? $this->dateToTimestamp($r->order_date) : null;
|
||||
$contract_data['finish_date'] = ($r->finish_date) ? $this->dateToTimestamp($r->finish_date) : null;
|
||||
$contract_data['cancel_date'] = ($r->cancel_date) ? $this->dateToTimestamp($r->cancel_date) : null;
|
||||
$contract_data['note'] = $r->note;
|
||||
|
||||
if($r->order_date) {
|
||||
$order_date = new DateTime("@" . $this->dateToTimestamp($r->order_date));
|
||||
$order_date->setTimezone(new DateTimeZone("Europe/Vienna"));
|
||||
$order_date->setTime(0, 0, 0);
|
||||
$contract_data['order_date'] = $order_date->getTimestamp();
|
||||
}
|
||||
|
||||
if($r->finish_date) {
|
||||
$finish_date = new DateTime("@" . $this->dateToTimestamp($r->finish_date));
|
||||
$finish_date->setTimezone(new DateTimeZone("Europe/Vienna"));
|
||||
$finish_date->setTime(0, 0, 0);
|
||||
$contract_data['finish_date'] = $finish_date->getTimestamp();
|
||||
}
|
||||
|
||||
if($r->cancel_date) {
|
||||
$cancel_date = new DateTime("@" . $this->dateToTimestamp($r->cancel_date));
|
||||
$cancel_date->setTimezone(new DateTimeZone("Europe/Vienna"));
|
||||
$cancel_date->setTime(0, 0, 0);
|
||||
$contract_data['cancel_date'] = $cancel_date->getTimestamp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//var_dump($contract_data);exit;
|
||||
|
||||
@@ -513,7 +537,7 @@ class ContractController extends mfBaseController
|
||||
$this->layout()->setFlash("Bitte Produkt auswählen.", "error");
|
||||
return $this->addAction();
|
||||
}
|
||||
if (!$contract_data['billing_period']) {
|
||||
if (!in_array($contract_data['billing_period'], [0,1,12])) {
|
||||
$this->layout()->setFlash("Bitte Rechnungsperiode auswählen.", "error");
|
||||
return $this->addAction();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class ContractModel {
|
||||
public $product_external_id;
|
||||
public $price = null;
|
||||
public $price_setup = null;
|
||||
public $vatrate = null;
|
||||
public $price_nne = null;
|
||||
public $price_nbe = null;
|
||||
public $billing_delay = null;
|
||||
|
||||
@@ -87,7 +87,7 @@ class ContractqueueModel {
|
||||
$data["order_id"] = $order->id;
|
||||
$data["orderproduct_id"] = $op->id;
|
||||
$data["owner_id"] = $order->owner_id;
|
||||
$data["billingaddress_id"] = $order->billingaddress_id;
|
||||
$data["billingaddress_id"] = ($order->billingaddress_id) ? $order->billingaddress_id : $order->owner_id;
|
||||
$data["termination_id"] = ($op->termination_id) ? $op->termination_id : null;
|
||||
$data["product_id"] = $op->product_id;
|
||||
$data["product_name"] = $product->name;
|
||||
|
||||
60
application/Invoice/Invoice.php
Normal file
60
application/Invoice/Invoice.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
class Invoice extends mfBaseModel {
|
||||
private $positions;
|
||||
|
||||
public function getProperty($name) {
|
||||
if($this->$name == null) {
|
||||
|
||||
if(!$this->id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if($name == "positions") {
|
||||
$positions = InvoicepositionModel::search(["invoice_id" => $this->id]);
|
||||
$this->positions = $positions;
|
||||
return $this->positions;
|
||||
}
|
||||
|
||||
if($name == "creator") {
|
||||
$this->creator = mfValuecache::singleton()->get("Worker-id-".$this->create_by);
|
||||
if($this->creator === null) {
|
||||
$this->creator = new User($this->create_by);
|
||||
if($this->creator->id) {
|
||||
mfValuecache::singleton()->set("Worker-id-".$this->create_by, $this->creator);
|
||||
}
|
||||
}
|
||||
return $this->creator;
|
||||
}
|
||||
|
||||
if($name == "editor") {
|
||||
$this->editor = mfValuecache::singleton()->get("Worker-id-".$this->edit_by);
|
||||
if($this->editor === null) {
|
||||
$this->editor = new User($this->edit_by);
|
||||
if($this->editor->id) {
|
||||
mfValuecache::singleton()->set("Worker-id-".$this->edit_by, $this->editor);
|
||||
}
|
||||
}
|
||||
return $this->editor;
|
||||
}
|
||||
|
||||
$classname = ucfirst($name);
|
||||
$idfield = $name."_id";
|
||||
$this->$name = mfValuecache::singleton()->get("mfObjectmodel-$name-".$this->$idfield);
|
||||
if(!$this->$name) {
|
||||
$this->$name = new $classname($this->$idfield);
|
||||
}
|
||||
|
||||
if($this->$name->id) {
|
||||
mfValuecache::singleton()->set("mfObjectmodel-$name-".$this->$name->id, $this->$name);
|
||||
return $this->$name;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
||||
345
application/Invoice/InvoiceController.php
Normal file
345
application/Invoice/InvoiceController.php
Normal file
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
|
||||
class InvoiceController extends mfBaseController {
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$this->needlogin = true;
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
$this->me = $me;
|
||||
$this->layout()->set("me", $me);
|
||||
|
||||
if (!$me->is(["Admin"])) {
|
||||
$this->redirect("Dashboard");
|
||||
}
|
||||
}
|
||||
|
||||
protected function indexAction() {
|
||||
$this->layout()->setTemplate("Invoice/Index");
|
||||
|
||||
if ($this->request->resetFilter) {
|
||||
unset($_SESSION[MFAPPNAME . '-Invoice-filter']);
|
||||
}
|
||||
|
||||
$filter = [];
|
||||
if (is_array($this->request->filter)) {
|
||||
$filter = $this->request->filter;
|
||||
$_SESSION[MFAPPNAME . '-Invoice-filter'] = $filter;
|
||||
} else {
|
||||
if (array_key_exists(MFAPPNAME . '-Invoice-filter', $_SESSION) && count($_SESSION[MFAPPNAME . '-Invoice-filter'])) {
|
||||
$filter = $_SESSION[MFAPPNAME . '-Invoice-filter'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->layout->set("filter", $filter);
|
||||
$filter = $this->getPreparedFilter($filter);
|
||||
|
||||
// pagination defaults
|
||||
$pagination = [];
|
||||
$pagination['start'] = 0;
|
||||
$pagination['count'] = 50;
|
||||
$pagination['maxItems'] = 0;
|
||||
|
||||
if(is_numeric($this->request->s)) {
|
||||
$pagination['start'] = intval($this->request->s);
|
||||
}
|
||||
//var_dump($filter);exit;
|
||||
$pagination['maxItems'] = InvoiceModel::count($filter);
|
||||
$billings = InvoiceModel::search($filter, $pagination);
|
||||
|
||||
$this->layout()->set("invoices", $billings);
|
||||
$this->layout()->set("pagination", $pagination);
|
||||
}
|
||||
|
||||
private function getPreparedFilter($filter)
|
||||
{
|
||||
$new_filter = [];
|
||||
|
||||
if(array_key_exists("customer", $filter)) {
|
||||
if(array_key_exists("customer", $filter) && $filter["customer"]) {
|
||||
$kunde = $this->db()->escape($filter['customer']);
|
||||
if(!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = "";
|
||||
$new_filter['add-where'] .= " AND (company like '%$kunde%' OR firstname like '%$kunde%' OR lastname like '%$kunde%' OR concat(firstname, ' ', lastname) like '%$kunde%' OR concat(lastname, ' ', firstname) like '%$kunde%')";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("address", $filter)) {
|
||||
if(array_key_exists("address", $filter) && $filter["address"]) {
|
||||
$search = $this->db()->escape($filter['address']);
|
||||
if(!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = "";
|
||||
$new_filter['add-where'] .= " AND (street like '%$search%' OR zip like '%$search%' OR city like '%$search%' OR country like '%$search%')";
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($filter) && count($filter)) {
|
||||
foreach ($filter as $name => $value) {
|
||||
$new_filter[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $new_filter;
|
||||
}
|
||||
|
||||
protected function downloadInvoice() {
|
||||
$id = $this->request->id;
|
||||
if (!is_numeric($id) || !$id) {
|
||||
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
|
||||
$this->redirect("Invoice");
|
||||
}
|
||||
|
||||
$invoice = new Invoice($id);
|
||||
if (!$invoice->id) {
|
||||
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
|
||||
$this->redirect("Rechnung");
|
||||
}
|
||||
|
||||
|
||||
|
||||
$vat = [];
|
||||
|
||||
foreach($invoice->positions as $p) {
|
||||
if(!array_key_exists($p->vatrate, $vat)) {
|
||||
$vat[$p->vatrate] = 0;
|
||||
}
|
||||
$vat[$p->vatrate] += $p->price_gross - $p->price;
|
||||
}
|
||||
|
||||
$pdf_vars = [
|
||||
"invoice" => $invoice,
|
||||
"vat" => $vat
|
||||
];
|
||||
|
||||
/*$this->layout()->setTemplate("Invoice/Print.pdf");
|
||||
$this->layout()->set("invoice", $invoice);
|
||||
$this->layout()->set("vat", $vat);
|
||||
$this->layout()->set("ressourcePathPrefix", MFFANCYBASEURL."/");
|
||||
return true;*/
|
||||
|
||||
$pdf = new PdfForm("Invoice/Print.pdf", $pdf_vars);
|
||||
//$pdfpath = $pdf->render();
|
||||
$pdf->download($invoice->invoice_number.".pdf");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected function runInvoicingAction() {
|
||||
$i = 0;
|
||||
$p = 0;
|
||||
|
||||
// get pairs of owner_id and billingaddress_id, so each will be its own invoice
|
||||
foreach(BillingModel::getInvoiceBaseData(['invoice_id' => null]) as $base) {
|
||||
//var_dump($base); continue;
|
||||
$owner_id = $base["owner_id"];
|
||||
$billingaddress_id = $base["billingaddress_id"];
|
||||
$billing_type = $base["billing_type"];
|
||||
$billing_delivery = $base["billing_delivery"];
|
||||
|
||||
$bill_positions = [];
|
||||
$credit_positions = [];
|
||||
|
||||
$billing_rows = BillingModel::search([
|
||||
"owner_id" => $owner_id,
|
||||
"billingaddress_id" => $billingaddress_id,
|
||||
"billing_type" => $billing_type,
|
||||
"billing_delivery" => $billing_delivery,
|
||||
"invoice_id" => null]);
|
||||
|
||||
if(!count($billing_rows)) {
|
||||
die("Keine nicht verrechneten Billing records für billingaddress_id");
|
||||
}
|
||||
|
||||
//var_dump($owner_id, $billingaddress_id, $bills);exit;
|
||||
|
||||
$invoice_data = [];
|
||||
|
||||
foreach($billing_rows as $bill) {
|
||||
$vatrate = $bill->vatrate;
|
||||
$price = $bill->price;
|
||||
$price_total = $bill->price * $bill->amount;
|
||||
$price_gross = ($vatrate) ? $price_total + ($price_total / 100) * $vatrate : $price_total;
|
||||
$price_setup = $bill->price_setup;
|
||||
$price_setup_total = $bill->price_setup * $bill->amount;
|
||||
$price_setup_gross = ($vatrate) ? $price_setup_total + ($price_setup_total / 100) * $vatrate : $price_setup_total;
|
||||
$add_setup_position = ($price > 0 && $price_setup > 0);
|
||||
$is_setup_only = ($price < 0.00001 && $price_setup > 0);
|
||||
|
||||
$position_data = [];
|
||||
$position_data["billing_id"] = $bill->id;
|
||||
$position_data["contract_id"] = $bill->contract_id;
|
||||
$position_data["start_date"] = $bill->start_date;
|
||||
$position_data["end_date"] = $bill->end_date;
|
||||
$position_data["matchcode"] = $bill->matchcode;
|
||||
$position_data["product_id"] = $bill->product_id;
|
||||
$position_data["product_name"] = $bill->product_name;
|
||||
$position_data["product_info"] = $bill->product_info;
|
||||
$position_data["amount"] = $bill->amount;
|
||||
$position_data["billing_period"] = $bill->billing_period;
|
||||
|
||||
|
||||
if($is_setup_only) {
|
||||
$this->log->debug("Contract ID ". $bill->contract_id." is setup only");
|
||||
$position_data["price"] = $price_setup;
|
||||
$position_data["price_total"] = $price_setup_total;
|
||||
$position_data["price_gross"] = $price_setup_gross;
|
||||
$position_data["vatrate"] = $vatrate;
|
||||
$position_data["end_date"] = $position_data["start_date"];
|
||||
} else {
|
||||
$position_data["price"] = $price;
|
||||
$position_data["price_total"] = $price_total;
|
||||
$position_data["price_gross"] = $price_gross;
|
||||
$position_data["vatrate"] = $vatrate;
|
||||
}
|
||||
|
||||
$new_position = InvoicepositionModel::create($position_data);
|
||||
$bill_positions[] = $new_position;
|
||||
|
||||
if($add_setup_position) {
|
||||
$this->log->debug("Adding Setup Invoiceposition for Contract ID ". $bill->contract_id);
|
||||
$setup_data = $position_data;
|
||||
$setup_data["product_name"] = "Herstellungskosten ".$bill->product_name;
|
||||
$setup_data["product_info"] = "";
|
||||
$setup_data["price"] = $price_setup;
|
||||
$setup_data["price_total"] = $price_setup * $bill->amount;
|
||||
$setup_data["price_gross"] = $price_setup_gross;
|
||||
$setup_data["vatrate"] = $vatrate;
|
||||
$setup_data["end_date"] = $setup_data["start_date"];
|
||||
$setup_position = InvoicepositionModel::create($setup_data);
|
||||
$bill_positions[] = $setup_position;
|
||||
}
|
||||
|
||||
|
||||
/*if($bill->price >= 0 || $bill->price_setup >= 0) {
|
||||
$bill_positions[] = InvoicepositionModel::create($position_data);
|
||||
} else {
|
||||
$credit_positions[] = InvoicepositionModel::create($position_data);;
|
||||
}*/
|
||||
|
||||
$invoice_data["owner_id"] = $owner_id;
|
||||
$invoice_data["billingaddress_id"] = $billingaddress_id;
|
||||
$invoice_data["customer_number"] = $bill->customer_number;
|
||||
$invoice_data["company"] = $bill->company;
|
||||
$invoice_data["firstname"] = $bill->firstname;
|
||||
$invoice_data["lastname"] = $bill->lastname;
|
||||
$invoice_data["street"] = $bill->street;
|
||||
$invoice_data["zip"] = $bill->zip;
|
||||
$invoice_data["city"] = $bill->city;
|
||||
$invoice_data["country"] = $bill->country;
|
||||
$invoice_data["email"] = $bill->email;
|
||||
$invoice_data["uid"] = $bill->uid;
|
||||
$invoice_data["billing_type"] = $billing_type;
|
||||
$invoice_data["billing_delivery"] = $billing_delivery;
|
||||
$invoice_data["bank_account_bank"] = $bill->bank_account_bank;
|
||||
$invoice_data["bank_account_owner"] = $bill->bank_account_owner;
|
||||
$invoice_data["bank_account_iban"] = $bill->bank_account_iban;
|
||||
$invoice_data["bank_account_bic"] = $bill->bank_account_bic;
|
||||
$invoice_data["total"] = 0;
|
||||
$invoice_data["total_gross"] = 0;
|
||||
$invoice_data["total_vat"] = 0;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//var_dump($bill_positions, $credit_positions);exit;
|
||||
|
||||
|
||||
// create Invoice
|
||||
$invoice = InvoiceModel::create($invoice_data);
|
||||
$invoice->startTransaction();
|
||||
|
||||
try {
|
||||
if(!$invoice->save()) {
|
||||
$invoice->rollbackTransaction();
|
||||
die("Error saving Invoice");
|
||||
}
|
||||
|
||||
$total_net = 0;
|
||||
$total_gross = 0;
|
||||
$total_vat = 0;
|
||||
|
||||
foreach($bill_positions as $position) {
|
||||
// on error: rollback transaction
|
||||
// add Invoice::id to Invoiceposition
|
||||
$position->invoice_id = $invoice->id;
|
||||
|
||||
|
||||
if(!$position->vatrate) {
|
||||
$total_net += $position->price_total;
|
||||
} else {
|
||||
$total_vat += ($position->price_total / 100) * $position->vatrate;
|
||||
$total_net += $position->price_total;
|
||||
$total_gross += $position->price_gross;
|
||||
}
|
||||
|
||||
// save Invoiceposition
|
||||
if(!$position->save()) {
|
||||
$invoice->rollbackTransaction();
|
||||
die("Error saving Invoiceposition");
|
||||
}
|
||||
|
||||
// ad Invoice::id to Bill
|
||||
$bill = new Billing($position->billing_id);
|
||||
if(!$bill->id) {
|
||||
$invoice->rollbackTransaction();
|
||||
die("Bill for Invoiceposition not found");
|
||||
}
|
||||
$bill->invoice_id = $invoice->id;
|
||||
|
||||
if(!$bill->save()) {
|
||||
$invoice->rollbackTransaction();
|
||||
die("error saving invoice_id to bill");
|
||||
}
|
||||
$p++;
|
||||
|
||||
}
|
||||
|
||||
$invoice->total = $total_net;
|
||||
$invoice->total_gross = $total_gross;
|
||||
$invoice->total_vat = $total_vat;
|
||||
|
||||
if(!$invoice->save()) {
|
||||
$invoice->rollbackTransaction();
|
||||
die("Error saving totals in Invoice");
|
||||
}
|
||||
// generate Invoice number
|
||||
|
||||
$new_num = InvoiceModel::getNextInvoiceNUmber();
|
||||
$invoice->invoice_number = $new_num;
|
||||
$invoice->invoice_date = date("U");
|
||||
|
||||
if(!$invoice->save()) {
|
||||
$invoice->rollbackTransaction();
|
||||
die("Error saving Invoice number and date");
|
||||
}
|
||||
|
||||
// commit transaction
|
||||
$invoice->commitTransaction();
|
||||
$i++;
|
||||
} catch (Exception $e) {
|
||||
if($invoice) {
|
||||
$invoice->rollbackTransaction();
|
||||
}
|
||||
|
||||
die("Error saving Invoice!\n");
|
||||
|
||||
}
|
||||
|
||||
// Create Invoice PDF
|
||||
|
||||
|
||||
// if billing_delivery == paper -> add to pdf collection
|
||||
|
||||
// else -> send by email
|
||||
|
||||
//var_dump($invoice);
|
||||
//exit;
|
||||
}
|
||||
|
||||
$this->layout()->setFlash("$i Rechnungen mit $p Rechnungspositionen erstellt");
|
||||
$this->redirect("Invoice");
|
||||
|
||||
}
|
||||
}
|
||||
340
application/Invoice/InvoiceModel.php
Normal file
340
application/Invoice/InvoiceModel.php
Normal file
@@ -0,0 +1,340 @@
|
||||
<?php
|
||||
|
||||
class InvoiceModel {
|
||||
public $invoice_number;
|
||||
public $invoice_date;
|
||||
public $billingaddress_id;
|
||||
public $customer_number;
|
||||
public $company;
|
||||
public $firstname;
|
||||
public $lastname;
|
||||
public $street;
|
||||
public $zip;
|
||||
public $city;
|
||||
public $country;
|
||||
public $email;
|
||||
public $uid;
|
||||
public $billing_type;
|
||||
public $billing_delivery;
|
||||
public $bank_account_bank;
|
||||
public $bank_account_owner;
|
||||
public $bank_account_iban;
|
||||
public $bank_account_bic;
|
||||
public $total;
|
||||
public $total_gross;
|
||||
public $total_vat;
|
||||
public $create_by;
|
||||
public $edit_by;
|
||||
public $create;
|
||||
public $edit;
|
||||
|
||||
|
||||
public static function create(Array $data) {
|
||||
$model = new Invoice();
|
||||
|
||||
foreach($data as $field => $value) {
|
||||
if(property_exists(get_called_class(), $field)) {
|
||||
$model ->$field = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
|
||||
if($model->create_by === null) {
|
||||
$model->create_by = $me->id;
|
||||
}
|
||||
if($model->edit_by === null) {
|
||||
$model->edit_by = $me->id;
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
public static function getNextInvoiceNUmber() {
|
||||
$last_invoice_num = self::getLastInvoiceNumber();
|
||||
|
||||
if(!$last_invoice_num) {
|
||||
return TT_FIRST_INVOICE_NUM;
|
||||
}
|
||||
|
||||
$year_part = 0;
|
||||
$num_part = 0;
|
||||
|
||||
$m = [];
|
||||
if(preg_match('/^RN(\d+)-X(\d+)$/', $last_invoice_num, $m)) {
|
||||
if(array_key_exists(1, $m)) {
|
||||
$year_part = $m[1];
|
||||
if(array_key_exists(2, $m)) {
|
||||
$num_part = $m[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!$year_part || !$num_part) {
|
||||
die("NO LAST INVOICE NUMBER!!!");
|
||||
}
|
||||
|
||||
//var_dump($year_part, $num_part);exit;
|
||||
if(date("Y") == $year_part) {
|
||||
$new_year_part = $year_part;
|
||||
$new_num_part = $num_part + 1;
|
||||
} else {
|
||||
$new_year_part = date("Y");
|
||||
$new_num_part = 1;
|
||||
}
|
||||
|
||||
$new_invoice_num = "RN$new_year_part-X".str_pad($new_num_part,"6", "0", STR_PAD_LEFT);
|
||||
return $new_invoice_num;
|
||||
}
|
||||
|
||||
public static function getLastInvoiceNumber() {
|
||||
$last_invoice = self::getLast(["invoice_number" => true]);
|
||||
if(!$last_invoice || !$last_invoice->invoice_number) {
|
||||
return false;
|
||||
}
|
||||
return $last_invoice->invoice_number;
|
||||
}
|
||||
|
||||
public static function getAll() {
|
||||
$items = [];
|
||||
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$res = $db->select("Invoice", "*", "1 = 1 ORDER BY invoice_number");
|
||||
if($db->num_rows($res)) {
|
||||
while($data = $db->fetch_object($res)) {
|
||||
$items[] = new Invoice($data);
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
|
||||
}
|
||||
|
||||
public static function getFirst($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT * FROM Invoice
|
||||
WHERE $where
|
||||
ORDER BY invoice_number LIMIT 1";
|
||||
//var_dump($sql);exit;
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
$data = $db->fetch_object($res);
|
||||
$item = new Invoice($data);
|
||||
if($item->id) {
|
||||
return $item;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getLast($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT * FROM Invoice
|
||||
WHERE $where
|
||||
ORDER BY invoice_number DESC LIMIT 1";
|
||||
|
||||
//mfLoghandler::singleton()->debug($sql);
|
||||
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
$data = $db->fetch_object($res);
|
||||
$item = new Invoice($data);
|
||||
if($item->id) {
|
||||
return $item;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function count($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT COUNT(*) as cnt FROM Invoice
|
||||
WHERE $where";
|
||||
|
||||
//mfLoghandler::singleton()->debug($sql);
|
||||
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
$data = $db->fetch_object($res);
|
||||
return $data->cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function search($filter, $limit = false, $order = false) {
|
||||
//var_dump($filter);exit;
|
||||
$items = [];
|
||||
|
||||
if(!$order) {
|
||||
$order = "invoice_number ASC";
|
||||
}
|
||||
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT * FROM Invoice
|
||||
WHERE $where
|
||||
ORDER BY $order";
|
||||
|
||||
if(is_array($limit) && count($limit)) {
|
||||
if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
|
||||
$sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
|
||||
} elseif(is_numeric($limit['count'])) {
|
||||
$sql .= " LIMIT ".$limit['count'];
|
||||
}
|
||||
}
|
||||
|
||||
mfLoghandler::singleton()->debug($sql);
|
||||
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
while($data = $db->fetch_object($res)) {
|
||||
$items[$data->id] = new Invoice($data);
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private static function getSqlFilter($filter) {
|
||||
$where = "1=1 ";
|
||||
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
//var_dump($filter);exit;
|
||||
|
||||
if(array_key_exists("id", $filter)) {
|
||||
$id = $filter['id'];
|
||||
if(is_numeric($id)) {
|
||||
$where .= " AND Invoice.id like '%$id%'";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("invoice_number", $filter)) {
|
||||
$invoice_number = $filter['invoice_number'];
|
||||
if($invoice_number === true) {
|
||||
$where .= " AND Invoice.invoice_number IS NOT NULL AND Invoice.invoice_number <> ''";
|
||||
} elseif($invoice_number) {
|
||||
$invoice_number = $db->escape($invoice_number);
|
||||
$where .= " AND Invoice.invoice_number='$invoice_number'";
|
||||
} elseif($invoice_number === null || $invoice_number === false) {
|
||||
$where .= " AND Invoice.invoice_number IS NULL";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("invoice_date", $filter)) {
|
||||
$invoice_date = $filter['invoice_date'];
|
||||
if($invoice_date) {
|
||||
$where .= " AND Invoice.invoice_date='$invoice_date'";
|
||||
} elseif($invoice_date === null || $invoice_date === false) {
|
||||
$where .= " AND Invoice.invoice_date IS NULL";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(array_key_exists("billingaddress_id", $filter)) {
|
||||
$Invoiceaddress_id = $filter['billingaddress_id'];
|
||||
if(is_numeric($Invoiceaddress_id)) {
|
||||
$where .= " AND Invoice.billingaddress_id=$Invoiceaddress_id";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("customer_number", $filter)) {
|
||||
$customer_number = $filter['customer_number'];
|
||||
if(is_numeric($customer_number)) {
|
||||
$where .= " AND Invoice.customer_number LIKE $customer_number";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("company", $filter)) {
|
||||
$company = FronkDB::singleton()->escape($filter["company"]);
|
||||
if ($company) {
|
||||
$where .= " AND company like '%$company%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("firstname", $filter)) {
|
||||
$firstname = FronkDB::singleton()->escape($filter["firstname"]);
|
||||
if ($firstname) {
|
||||
$where .= " AND firstname like '%$firstname%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("lastname", $filter)) {
|
||||
$lastname = FronkDB::singleton()->escape($filter["lastname"]);
|
||||
if ($lastname) {
|
||||
$where .= " AND lastname like '%$lastname%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("mergedName", $filter)) {
|
||||
$name = FronkDB::singleton()->escape($filter["mergedName"]);
|
||||
if ($name) {
|
||||
$where .= " AND (CONCAT(firstname, ' ', lastname) like '%$name%' OR CONCAT(lastname, ' ', firstname) like '%$name%' )";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("street", $filter)) {
|
||||
$street = FronkDB::singleton()->escape($filter["street"]);
|
||||
if ($street) {
|
||||
$where .= " AND street like '%$street%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("zip", $filter)) {
|
||||
$zip = FronkDB::singleton()->escape($filter["zip"]);
|
||||
if ($zip) {
|
||||
$where .= " AND zip like '%$zip%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("city", $filter)) {
|
||||
$city = FronkDB::singleton()->escape($filter["city"]);
|
||||
if ($city) {
|
||||
$where .= " AND city like '%$city%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("country", $filter)) {
|
||||
$country = FronkDB::singleton()->escape($filter["country"]);
|
||||
if ($country) {
|
||||
$where .= " AND country like '%$country%'";
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists("email", $filter)) {
|
||||
$email = FronkDB::singleton()->escape($filter["email"]);
|
||||
if ($email) {
|
||||
$where .= " AND email like '%$email%'";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(array_key_exists("add-where", $filter)) {
|
||||
$where .= " ".$filter['add-where'];
|
||||
}
|
||||
|
||||
|
||||
if(array_key_exists("Invoice_period", $filter)) {
|
||||
$Invoice_period = $filter['Invoice_period'];
|
||||
if(is_numeric($Invoice_period)) {
|
||||
$where .= " AND Invoice.Invoice_period = $Invoice_period";
|
||||
}
|
||||
}
|
||||
|
||||
//var_dump($filter, $where);exit;
|
||||
return $where;
|
||||
}
|
||||
|
||||
}
|
||||
34
application/Invoiceposition/Invoiceposition.php
Normal file
34
application/Invoiceposition/Invoiceposition.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
class Invoiceposition extends mfBaseModel {
|
||||
|
||||
|
||||
public function __clone() {
|
||||
$me = new User;
|
||||
$me->loadMe();
|
||||
|
||||
$old_id = $this->id;
|
||||
$this->id = null;
|
||||
|
||||
|
||||
// cleanup data
|
||||
$this->invoice_id = null;
|
||||
$this->create_by = $me->id;
|
||||
$this->edit_by = $me->id;
|
||||
|
||||
$this->create = null;
|
||||
$this->edit = null;
|
||||
$this->saved = 0;
|
||||
$this->mode = "new";
|
||||
$this->_old_data = new StdClass();
|
||||
|
||||
/*$this->save();
|
||||
|
||||
if($old_id == $this->id) {
|
||||
$this->log->error("save() of cloned Contract $old_id failed!");
|
||||
throw new Exception("Saving clone failed.");
|
||||
}*/
|
||||
|
||||
//$this->log->debug("Cloned Invoiceposition $old_id");
|
||||
}
|
||||
}
|
||||
165
application/Invoiceposition/InvoicepositionModel.php
Normal file
165
application/Invoiceposition/InvoicepositionModel.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
class InvoicepositionModel {
|
||||
public $invoice_id;
|
||||
public $billing_id;
|
||||
public $contract_id;
|
||||
public $start_date;
|
||||
public $end_date;
|
||||
public $matchcode;
|
||||
public $product_id;
|
||||
public $product_name;
|
||||
public $product_info;
|
||||
public $amount;
|
||||
public $price;
|
||||
public $price_total;
|
||||
public $price_gross;
|
||||
public $vatrate;
|
||||
public $billing_period;
|
||||
|
||||
public $create_by;
|
||||
public $edit_by;
|
||||
public $create;
|
||||
public $edit;
|
||||
|
||||
|
||||
public static function create(Array $data) {
|
||||
$model = new Invoiceposition();
|
||||
|
||||
foreach($data as $field => $value) {
|
||||
if(property_exists(get_called_class(), $field)) {
|
||||
$model ->$field = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
|
||||
if($model->create_by === null) {
|
||||
$model->create_by = $me->id;
|
||||
}
|
||||
if($model->edit_by === null) {
|
||||
$model->edit_by = $me->id;
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
public static function getAll() {
|
||||
$items = [];
|
||||
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$res = $db->select("Invoiceposition", "*", "1 = 1 ORDER BY invoice_id,contract_id,start_date,matchcode");
|
||||
if($db->num_rows($res)) {
|
||||
while($data = $db->fetch_object($res)) {
|
||||
$items[] = new Invoiceposition($data);
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
|
||||
}
|
||||
|
||||
public static function getFirst($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT * FROM Invoiceposition
|
||||
WHERE $where
|
||||
ORDER BY invoice_id,contract_id,start_date,matchcode LIMIT 1";
|
||||
//var_dump($sql);exit;
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
$data = $db->fetch_object($res);
|
||||
$item = new Invoiceposition($data);
|
||||
if($item->id) {
|
||||
return $item;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function count($filter) {
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT COUNT(*) as cnt FROM Invoiceposition
|
||||
WHERE $where";
|
||||
|
||||
//mfLoghandler::singleton()->debug($sql);
|
||||
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
$data = $db->fetch_object($res);
|
||||
return $data->cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function search($filter, $limit = false, $order = false) {
|
||||
//var_dump($filter);exit;
|
||||
$items = [];
|
||||
|
||||
if(!$order) {
|
||||
$order = "invoice_id,contract_id,start_date,matchcode ASC";
|
||||
}
|
||||
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
$where = self::getSqlFilter($filter);
|
||||
$sql = "SELECT * FROM Invoiceposition
|
||||
WHERE $where
|
||||
ORDER BY $order";
|
||||
|
||||
if(is_array($limit) && count($limit)) {
|
||||
if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
|
||||
$sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
|
||||
} elseif(is_numeric($limit['count'])) {
|
||||
$sql .= " LIMIT ".$limit['count'];
|
||||
}
|
||||
}
|
||||
|
||||
mfLoghandler::singleton()->debug($sql);
|
||||
|
||||
$res = $db->query($sql);
|
||||
if($db->num_rows($res)) {
|
||||
while($data = $db->fetch_object($res)) {
|
||||
$items[$data->id] = new Invoiceposition($data);
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private static function getSqlFilter($filter) {
|
||||
$where = "1=1 ";
|
||||
|
||||
$db = FronkDB::singleton();
|
||||
|
||||
//var_dump($filter);exit;
|
||||
|
||||
if(array_key_exists("id", $filter)) {
|
||||
$id = $filter['id'];
|
||||
if(is_numeric($id)) {
|
||||
$where .= " AND Invoiceposition.id = $id";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("invoice_id", $filter)) {
|
||||
$invoice_id = $filter['invoice_id'];
|
||||
if(is_numeric($invoice_id)) {
|
||||
$where .= " AND Invoiceposition.invoice_id=$invoice_id";
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists("add-where", $filter)) {
|
||||
$where .= " ".$filter['add-where'];
|
||||
}
|
||||
|
||||
//var_dump($filter, $where);exit;
|
||||
return $where;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -232,6 +232,7 @@ class UserController extends mfBaseController
|
||||
$user->permissions->canVoipnumbering = "false";
|
||||
$user->permissions->canPreorder = "false";
|
||||
$user->permissions->canOrder = "false";
|
||||
$user->permissions->canBilling = "false";
|
||||
$user->permissions->canFibu = "false";
|
||||
$user->permissions->canStatistics = "false";
|
||||
|
||||
|
||||
@@ -10,16 +10,10 @@ final class CreateBilling extends AbstractMigration
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$table = $this->table("Billing");
|
||||
$table->addColumn("invoice_id", "integer", ["null" => true, "default" => null]);
|
||||
$table->addColumn("invoice_date", "date", ["null" => true, "default" => null]);
|
||||
$table->addColumn("contract_id", "integer", ["null" => false]);
|
||||
$table->addColumn("start_date", "date", ["null" => false]);
|
||||
/*$table->addColumn("start_year", "integer", ["null" => false]);
|
||||
$table->addColumn("start_month", "integer", ["null" => false]);
|
||||
$table->addColumn("start_day", "integer", ["null" => false]);*/
|
||||
$table->addColumn("end_date", "date", ["null" => false]);
|
||||
/*$table->addColumn("end_year", "integer", ["null" => false]);
|
||||
$table->addColumn("end_month", "integer", ["null" => false]);
|
||||
$table->addColumn("end_day", "integer", ["null" => false]);*/
|
||||
$table->addColumn("owner_id", "integer", ["null" => false]);
|
||||
$table->addColumn("billingaddress_id", "integer", ["null" => false]);
|
||||
$table->addColumn("customer_number", "integer", ["null" => false]);
|
||||
$table->addColumn("company", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
@@ -44,6 +38,7 @@ final class CreateBilling extends AbstractMigration
|
||||
$table->addColumn("amount", "decimal", ["null" => false, "precision" => 9, "scale" => 6]);
|
||||
$table->addColumn("price", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$table->addColumn("price_setup", "decimal", ["null" => false, "default" => 0, "precision" => 14, "scale" => 4]);
|
||||
$table->addColumn("total_vat", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$table->addColumn("billing_period", "integer", ["null" => false, "default" => 0]);
|
||||
|
||||
$table->addColumn("create_by", "integer", ["null" => false]);
|
||||
|
||||
80
db/migrations/20240625162005_create_invoice_tables.php
Normal file
80
db/migrations/20240625162005_create_invoice_tables.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreateInvoiceTables extends AbstractMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$invoice = $this->table("Invoice");
|
||||
|
||||
$invoice->addColumn("invoice_number", "string", ["null" => true, "default" => null]); // RN2024-X000001
|
||||
$invoice->addColumn("invoice_date", "integer", ["default" => 0]);
|
||||
$invoice->addColumn("billingaddress_id", "integer", ["null" => false]);
|
||||
$invoice->addColumn("customer_number", "integer", ["null" => false]);
|
||||
$invoice->addColumn("company", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
$invoice->addColumn("firstname", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
$invoice->addColumn("lastname", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
$invoice->addColumn("street", "string", ["null" => false, "length" => 1024]);
|
||||
$invoice->addColumn("zip", "string", ["null" => false, "length" => 1024]);
|
||||
$invoice->addColumn("city", "string", ["null" => false, "length" => 1024]);
|
||||
$invoice->addColumn("country", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
$invoice->addColumn("email", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
$invoice->addColumn("uid", "string", ["null" => true, "default" => null, "length" => 1024]);
|
||||
$invoice->addColumn("billing_type", "enum", ["null" => false, "values" => "invoice,sepa"]);
|
||||
$invoice->addColumn("billing_delivery", "enum", ["null" => false, "values" => "email,paper"]);
|
||||
$invoice->addColumn("bank_account_bank", "string", ["null" => true, "default" => null, "length" => 255]);
|
||||
$invoice->addColumn("bank_account_owner", "string", ["null" => true, "default" => null, "length" => 255]);
|
||||
$invoice->addColumn("bank_account_iban", "string", ["null" => true, "default" => null, "length" => 255]);
|
||||
$invoice->addColumn("bank_account_bic", "string", ["null" => true, "default" => null, "length" => 255]);
|
||||
$invoice->addColumn("total", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$invoice->addColumn("total_gross", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$invoice->addColumn("vatrate", "decimal", ["null" => false, "default" => 0, "precision" => 6, "scale" => 2]);
|
||||
$invoice->addColumn("create_by", "integer", ["null" => false]);
|
||||
$invoice->addColumn("edit_by", "integer", ["null" => false]);
|
||||
$invoice->addColumn("create", "integer", ["null" => false]);
|
||||
$invoice->addColumn("edit", "integer", ["null" => false]);
|
||||
$invoice->create();
|
||||
|
||||
$ip = $this->table("Invoiceposition");
|
||||
$ip->addColumn("invoice_id", "integer", ["null" => true, "default" => null]);
|
||||
$ip->addColumn("billing_id", "integer", ["null" => true, "default" => null]);
|
||||
$ip->addColumn("contract_id", "integer", ["null" => false]);
|
||||
$ip->addColumn("start_date", "date", ["null" => false]);
|
||||
$ip->addColumn("end_date", "date", ["null" => true, "default" => null]);
|
||||
$ip->addColumn("matchcode", "string", ["null" => true, "default" => null, "length" => 255]);
|
||||
$ip->addColumn("product_id", "integer", ["null" => false]);
|
||||
$ip->addColumn("product_name", "string", ["null" => false, "length" => 255]);
|
||||
$ip->addColumn("product_info", "text", ["null" => true, "default" => null]);
|
||||
$ip->addColumn("amount", "decimal", ["null" => false, "precision" => 9, "scale" => 6]);
|
||||
$ip->addColumn("price", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$ip->addColumn("price_total", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$ip->addColumn("price_gross", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
|
||||
$ip->addColumn("vatrate", "decimal", ["null" => false, "default" => 0, "precision" => 6, "scale" => 2]);
|
||||
$ip->addColumn("billing_period", "integer", ["null" => false, "default" => 0]);
|
||||
$ip->addColumn("create_by", "integer", ["null" => false]);
|
||||
$ip->addColumn("edit_by", "integer", ["null" => false]);
|
||||
$ip->addColumn("create", "integer", ["null" => false]);
|
||||
$ip->addColumn("edit", "integer", ["null" => false]);
|
||||
$ip->create();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$this->table("InvoicePosition")->drop()->save();
|
||||
$this->table("Invoice")->drop()->save();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
33
db/migrations/20240625164727_contract_add_vat.php
Normal file
33
db/migrations/20240625164727_contract_add_vat.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class ContractAddVat extends AbstractMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$table = $this->table("Contract");
|
||||
$table->addColumn("vatrate", "decimal", ["null" => false, "default" => 0, "precision" => 6, "scale" => 2, "after" => "price_setup"]);
|
||||
$table->update();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$table = $this->table("Contract");
|
||||
$table->removeColumn("vatrate");
|
||||
$table->update();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class WorkerPermissionAddBilling extends AbstractMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$table = $this->table("WorkerPermission");
|
||||
$table->addColumn("canBilling", "enum", ["null" => false,"values" => 'false,true', "default" => "false", "after" => "canOrder"]);
|
||||
$table->update();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if($this->getEnvironment() == "thetool") {
|
||||
$this->table("WorkerPermission")->removeColumn("canBilling")->save();
|
||||
}
|
||||
|
||||
if($this->getEnvironment() == "addressdb") {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,11 @@ $l['contract.relocation'] = "Umzug";
|
||||
$l['contract.productchange'] = "Produktwechsel";
|
||||
$l['contract.credit'] = "Gutschrift";
|
||||
|
||||
$l["billing_period.0"] = "Einmalig";
|
||||
$l["billing_period.1"] = "Monatlich";
|
||||
$l["billing_period.12"] = "Jährlich";
|
||||
$l["billing_period.24"] = "Zweijährlich";
|
||||
$l["billing_period.46"] = "Dreijährlich";
|
||||
|
||||
$l['cc.oesterreich'] = "AT";
|
||||
$l['cc.oestereich'] = "AT";
|
||||
|
||||
BIN
public/assets/images/xinon-dark.png
Normal file
BIN
public/assets/images/xinon-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
174
public/css/sknx_print.css
Normal file
174
public/css/sknx_print.css
Normal file
@@ -0,0 +1,174 @@
|
||||
* {
|
||||
font-family: "Open Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
margin: 24pt;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size:9pt;
|
||||
height:100%;
|
||||
margin-top: 50pt;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:13pt;
|
||||
}
|
||||
|
||||
#adressen {
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
font-size:10pt;
|
||||
}
|
||||
#adressen tr td {
|
||||
width:40%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#adressen .left {
|
||||
padding-top: 136pt;
|
||||
width:55%;
|
||||
}
|
||||
#adressen .right {
|
||||
width:45%;
|
||||
}
|
||||
|
||||
.adresse {
|
||||
border:none;
|
||||
text-align:left;
|
||||
line-height: 11pt;
|
||||
}
|
||||
.adresse div {
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
.header_sknx div {
|
||||
font-size:8pt;
|
||||
line-height:10pt;
|
||||
color:#505050;
|
||||
}
|
||||
|
||||
.header_sknx div b {
|
||||
font-size:11pt;
|
||||
line-height:12pt;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
table.position {
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
font-size:9pt;
|
||||
}
|
||||
table tr,
|
||||
table tr td {
|
||||
page-break-inside: avoid !important;
|
||||
break-inside: avoid !important;
|
||||
}
|
||||
table.position tr.head {
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
table.position tr.even {
|
||||
background-color:#f0f0f0;
|
||||
}
|
||||
table.position tr td,
|
||||
table.position tr th {
|
||||
text-align:center;
|
||||
padding-left:4pt;
|
||||
}
|
||||
table.position tr td.name,
|
||||
table.position tr th.name {
|
||||
text-align:left;
|
||||
width:50%;
|
||||
}
|
||||
table.position tr td.preis,
|
||||
table.position tr th.preis {
|
||||
text-align:right;
|
||||
}
|
||||
table.position tr td.freitext {
|
||||
text-align:left;
|
||||
padding-left:12pt;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#total {
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
font-size:10pt;
|
||||
margin-bottom: 14pt;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
#total td,
|
||||
#total th {
|
||||
width:50%;
|
||||
}
|
||||
#total th {
|
||||
text-align:left;
|
||||
}
|
||||
#total td {
|
||||
text-align:right;
|
||||
font-weight:bold;
|
||||
}
|
||||
#total tr.ust td,
|
||||
#total tr.ust th {
|
||||
font-size: 9pt;
|
||||
font-weight:normal;
|
||||
}
|
||||
|
||||
#total tr.netto {
|
||||
border-top:1px solid #000;
|
||||
}
|
||||
#total tr.brutto {
|
||||
border-top:1px solid #000;
|
||||
border-bottom:3px double #000;
|
||||
}
|
||||
#ausdruck td.beschriftung {
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
}
|
||||
#ausdruck td.text {
|
||||
font-size: 10pt;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
.dontsplit {
|
||||
page-break-inside:avoid;
|
||||
}
|
||||
.dontsplitafter {
|
||||
page-break-after:avoid;
|
||||
}
|
||||
.dontsplitbefore {
|
||||
page-break-before:avoid;
|
||||
}
|
||||
|
||||
tbody::after {
|
||||
content: ''; display: block;
|
||||
page-break-after: always;
|
||||
page-break-inside: avoid;
|
||||
page-break-before: avoid;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 8pt;
|
||||
}
|
||||
.ml-2 {
|
||||
margin-left: 12pt;
|
||||
}
|
||||
.pl-2 {
|
||||
padding-left: 8pt;
|
||||
}
|
||||
.pl-3 {
|
||||
padding-left: 12pt;
|
||||
}
|
||||
|
||||
.one-position {
|
||||
vertical-align: top;
|
||||
padding-bottom: 4pt;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ $tbms = 0;
|
||||
$tbys = 0;
|
||||
$tbs = 0;
|
||||
|
||||
foreach(BillingModel::search(["price>=" => 0]) as $bill) {
|
||||
foreach(BillingModel::search(["price>=" => 0, "start_date" => "2024-06-01"]) as $bill) {
|
||||
if($bill->billing_period == 1) {
|
||||
$tbms += $bill->price;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ $tbcms = 0;
|
||||
$tbcys = 0;
|
||||
$tbcs = 0;
|
||||
|
||||
foreach(BillingModel::search(["price<" => 0]) as $bill) {
|
||||
foreach(BillingModel::search(["price<" => 0, "start_date" => "2024-06-01"]) as $bill) {
|
||||
if($bill->billing_period == 1) {
|
||||
$tbcms += $bill->price;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user