| 1 | <?php
|
|---|
| 2 |
|
|---|
| 3 | class PageFinanceManage extends Page
|
|---|
| 4 | {
|
|---|
| 5 | function __construct(System $System)
|
|---|
| 6 | {
|
|---|
| 7 | parent::__construct($System);
|
|---|
| 8 | $this->Title = 'Správa financí';
|
|---|
| 9 | $this->ParentClass = 'PageFinance';
|
|---|
| 10 | }
|
|---|
| 11 |
|
|---|
| 12 | function Show(): string
|
|---|
| 13 | {
|
|---|
| 14 | $Output = '';
|
|---|
| 15 | if (!ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('Finance', 'Manage'))
|
|---|
| 16 | return 'Nemáte oprávnění';
|
|---|
| 17 |
|
|---|
| 18 | if (array_key_exists('Operation', $_GET)) $Operation = $_GET['Operation'];
|
|---|
| 19 | else $Operation = '';
|
|---|
| 20 | switch ($Operation)
|
|---|
| 21 | {
|
|---|
| 22 | case 'Recalculate':
|
|---|
| 23 | $Output .= ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->RecalculateMemberPayment();
|
|---|
| 24 | break;
|
|---|
| 25 | case 'ShowMonthlyPayment':
|
|---|
| 26 | $Output = $this->ShowMonthlyPayment();
|
|---|
| 27 | break;
|
|---|
| 28 | case 'ProcessMonthlyPayment':
|
|---|
| 29 | $Output = $this->ProcessMonthlyPayment();
|
|---|
| 30 | break;
|
|---|
| 31 | case 'GenerateBills':
|
|---|
| 32 | $Output = $this->GenerateBills();
|
|---|
| 33 | break;
|
|---|
| 34 | case 'RegenerateInvoice':
|
|---|
| 35 | $Output = $this->GenerateInvoice('AND (Id='.$_GET['i'].')');
|
|---|
| 36 | break;
|
|---|
| 37 | case 'RegenerateOperation':
|
|---|
| 38 | $Output = $this->GenerateOperation('AND (Id='.$_GET['i'].')');
|
|---|
| 39 | break;
|
|---|
| 40 | case 'SendPaymentEmail':
|
|---|
| 41 | $Output = $this->SendPaymentEmail($_GET['i']);
|
|---|
| 42 | break;
|
|---|
| 43 | default:
|
|---|
| 44 | //$Output .= '<a href="?Operation=Recalculate">Přepočet financí</a><br />';
|
|---|
| 45 | $Output .= '<a href="?Operation=ShowMonthlyPayment">Měsíční vyúčtování</a><br />';
|
|---|
| 46 | $Output .= '<a href="'.$this->System->Link('/finance/zivnost/').'">Živnost</a><br />';
|
|---|
| 47 | $Output .= '<a href="?Operation=GenerateBills">Generovat chybějící doklady</a><br />';
|
|---|
| 48 | $Output .= '<a href="'.$this->System->Link('/finance/import/').'">Import plateb</a><br />';
|
|---|
| 49 | }
|
|---|
| 50 | return $Output;
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | /* Get first day and last day of given billing period. Periods are aligned with year start/end. */
|
|---|
| 54 | function GetBillingPeriod(int $Period): array
|
|---|
| 55 | {
|
|---|
| 56 | $Time = time();
|
|---|
| 57 | $Year = date('Y', $Time);
|
|---|
| 58 |
|
|---|
| 59 | $MonthCount = ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->BillingPeriods[$Period]['MonthCount'];
|
|---|
| 60 | if ($MonthCount <= 0) return array('From' => NULL, 'To' => NULL, 'MonthCount' => 0);
|
|---|
| 61 | $MonthCurrent = date('n', $Time);
|
|---|
| 62 |
|
|---|
| 63 | /* Get start and end of aligned period */
|
|---|
| 64 | $MonthFrom = floor(($MonthCurrent - 1) / $MonthCount) * $MonthCount + 1;
|
|---|
| 65 | $MonthTo = $MonthFrom + $MonthCount - 1;
|
|---|
| 66 |
|
|---|
| 67 | /* Use period from current month to end month so months before current month are cut out */
|
|---|
| 68 | $MonthCount = $MonthTo - $MonthCurrent + 1;
|
|---|
| 69 | $MonthFrom = $MonthCurrent;
|
|---|
| 70 |
|
|---|
| 71 | /* Get first and last day of period */
|
|---|
| 72 | $PeriodFrom = mktime(0, 0, 0, $MonthFrom, 1, $Year);
|
|---|
| 73 | $PeriodTo = mktime(0, 0, 0, $MonthTo, date('t', mktime(0, 0, 0, $MonthTo, 1, $Year)), $Year);
|
|---|
| 74 |
|
|---|
| 75 | return array('From' => $PeriodFrom, 'To' => $PeriodTo, 'MonthCount' => $MonthCount);
|
|---|
| 76 | }
|
|---|
| 77 |
|
|---|
| 78 | function ShowMonthlyPayment(): string
|
|---|
| 79 | {
|
|---|
| 80 | if (!ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('Finance', 'Manage')) return 'Nemáte oprávnění';
|
|---|
| 81 | $SQL = 'SELECT `Member`.*, `MemberPayment`.`MonthlyTotal` AS `Monthly`, '.
|
|---|
| 82 | '`MemberPayment`.`Cash` AS `Cash`, '.
|
|---|
| 83 | '(SELECT GROUP_CONCAT(`Service`.`Name`) FROM `ServiceCustomerRel` LEFT JOIN `Service` '.
|
|---|
| 84 | 'ON `Service`.`Id`=`ServiceCustomerRel`.`Service` WHERE `ServiceCustomerRel`.`Customer`=`Member`.`Id` AND '.
|
|---|
| 85 | '`ServiceCustomerRel`.`ChangeAction` IS NULL) AS `ServicesNextMonth`, '.
|
|---|
| 86 | 'UNIX_TIMESTAMP(`Member`.`BillingPeriodLastDate`) AS `LastDate`, `Subject`.`Name` AS `SubjectName`, '.
|
|---|
| 87 | '`FinanceBillingPeriod`.`Name` AS `BillingPeriodName` '.
|
|---|
| 88 | 'FROM `MemberPayment` JOIN `Member` ON `Member`.`Id`=`MemberPayment`.`Member` JOIN `Subject` '.
|
|---|
| 89 | 'ON `Subject`.`Id`=`Member`.`Subject` LEFT JOIN `FinanceBillingPeriod` ON '.
|
|---|
| 90 | '`FinanceBillingPeriod`.`Id`=`Member`.`BillingPeriod` WHERE (`Member`.`Blocked` = 0)'.
|
|---|
| 91 | 'AND (`Member`.`BillingPeriod` > 1) AND (`MemberPayment`.`MonthlyTotal` != 0)';
|
|---|
| 92 |
|
|---|
| 93 | $DbResult = $this->Database->query('SELECT COUNT(*) FROM ('.$SQL.') AS T');
|
|---|
| 94 | $DbRow = $DbResult->fetch_row();
|
|---|
| 95 | $PageList = GetPageList('MonthlyPayment', $DbRow[0]);
|
|---|
| 96 |
|
|---|
| 97 | $Output = $PageList['Output'];
|
|---|
| 98 | $Output .= '<table class="WideTable" style="font-size: small;">';
|
|---|
| 99 |
|
|---|
| 100 | $TableColumns = array(
|
|---|
| 101 | array('Name' => 'SubjectName', 'Title' => 'Jméno'),
|
|---|
| 102 | array('Name' => 'Monthly', 'Title' => 'Platba'),
|
|---|
| 103 | array('Name' => 'Cash', 'Title' => 'Kredit'),
|
|---|
| 104 | array('Name' => 'LastDate', 'Title' => 'Poslední fakturace'),
|
|---|
| 105 | array('Name' => 'ServicesNextMonth', 'Title' => 'Služby'),
|
|---|
| 106 | array('Name' => 'BillingPeriodName', 'Title' => 'Perioda'),
|
|---|
| 107 | );
|
|---|
| 108 | $Order = GetOrderTableHeader('MonthlyPayment', $TableColumns, 'SubjectName', 0);
|
|---|
| 109 | $Output .= $Order['Output'];
|
|---|
| 110 |
|
|---|
| 111 | $Query = $SQL.' '.$Order['SQL'].$PageList['SQLLimit'];
|
|---|
| 112 |
|
|---|
| 113 | $DbResult = $this->Database->query($Query);
|
|---|
| 114 | while ($Row = $DbResult->fetch_assoc())
|
|---|
| 115 | {
|
|---|
| 116 | $Output .= '<tr>'.
|
|---|
| 117 | '<td>'.$Row['SubjectName'].'</td>'.
|
|---|
| 118 | '<td>'.$Row['Monthly'].'</td>'.
|
|---|
| 119 | '<td>'.$Row['Cash'].'</td>'.
|
|---|
| 120 | '<td>'.date('j.n.Y', $Row['LastDate']).'</td>'.
|
|---|
| 121 | '<td>'.$Row['ServicesNextMonth'].'</td>'.
|
|---|
| 122 | '<td>'.$Row['BillingPeriodName'].'</td>'.
|
|---|
| 123 | '</tr>';
|
|---|
| 124 | }
|
|---|
| 125 | $Output .= '</table>';
|
|---|
| 126 | $Output .= $PageList['Output'];
|
|---|
| 127 | $Output .= '<a href="?Operation=ProcessMonthlyPayment">Generovat faktury</a>';
|
|---|
| 128 | return $Output;
|
|---|
| 129 | }
|
|---|
| 130 |
|
|---|
| 131 | function InsertInvoice(string $Subject, string $TimeCreation, string $TimeDue, array $Items,
|
|---|
| 132 | array $Group, float $PeriodFrom, float $PeriodTo): string
|
|---|
| 133 | {
|
|---|
| 134 | global $LastInsertTime;
|
|---|
| 135 |
|
|---|
| 136 | $Finance = ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance;
|
|---|
| 137 |
|
|---|
| 138 | $Year = date('Y', $TimeCreation);
|
|---|
| 139 | $BillCode = ModuleDocument::Cast($this->System->GetModule('Document'))->GetNextDocumentLineNumberId($Group['DocumentLine'], $Year);
|
|---|
| 140 | $SumValue = 0;
|
|---|
| 141 | foreach ($Items as $Item) {
|
|---|
| 142 | $SumValue = $SumValue + $Item['Price'] * $Item['Quantity'];
|
|---|
| 143 | }
|
|---|
| 144 | $SumValue = round($SumValue, $Finance->Rounding);
|
|---|
| 145 | $this->Database->insert('FinanceInvoice', array(
|
|---|
| 146 | 'Subject' => $Subject, 'Time' => TimeToMysqlDateTime($TimeCreation),
|
|---|
| 147 | 'TimeDue' => TimeToMysqlDateTime($TimeDue), 'Value' => $SumValue * $Group['ValueSign'],
|
|---|
| 148 | 'BillCode' => $BillCode,
|
|---|
| 149 | 'PeriodFrom' => TimeToMysqlDate($PeriodFrom), 'PeriodTo' => TimeToMysqlDate($PeriodTo),
|
|---|
| 150 | 'Generate' => 1, 'Group' => $Group['Id']));
|
|---|
| 151 | $InvoiceId = $this->Database->insert_id;
|
|---|
| 152 | foreach ($Items as $Item)
|
|---|
| 153 | $this->Database->insert('FinanceInvoiceItem', array('FinanceInvoice' => $InvoiceId,
|
|---|
| 154 | 'Description' => $Item['Description'], 'Price' => $Item['Price'],
|
|---|
| 155 | 'Quantity' => $Item['Quantity'], 'VAT' => $Item['VAT']));
|
|---|
| 156 | //$LastInsertTime = $Time;
|
|---|
| 157 | //$this->CheckAdvancesAndLiabilities($Subject);
|
|---|
| 158 | return $InvoiceId;
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | function ProduceInvoices(): string
|
|---|
| 162 | {
|
|---|
| 163 | $Output = '';
|
|---|
| 164 |
|
|---|
| 165 | // Produce accounting items
|
|---|
| 166 | $DbResult = $this->Database->query('SELECT `Member`.*, `MemberPayment`.`MonthlyTotal` AS `MonthlyTotal`, '.
|
|---|
| 167 | 'UNIX_TIMESTAMP(`Member`.`BillingPeriodLastDate`) AS `BillingPeriodLastUnixTime`, `Subject`.`Name` AS `SubjectName`,'.
|
|---|
| 168 | '`MemberPayment`.`MonthlyPlus` AS `MonthlyPlus` '.
|
|---|
| 169 | 'FROM `MemberPayment` JOIN `Member` ON `Member`.`Id`=`MemberPayment`.`Member` '.
|
|---|
| 170 | 'JOIN `Subject` ON `Subject`.`Id`=`Member`.`Subject`');
|
|---|
| 171 | while ($Member = $DbResult->fetch_assoc())
|
|---|
| 172 | {
|
|---|
| 173 | $Output .= $Member['SubjectName'].': ';
|
|---|
| 174 | $Period = $this->GetBillingPeriod($Member['BillingPeriod']);
|
|---|
| 175 |
|
|---|
| 176 | // Check if need to produce new invoice for customer
|
|---|
| 177 | if (($Period['MonthCount'] > 0) and ($Member['Blocked'] == 0) and
|
|---|
| 178 | ($Period['From'] > $Member['BillingPeriodLastUnixTime']))
|
|---|
| 179 | {
|
|---|
| 180 | $InvoiceItems = array();
|
|---|
| 181 | $MonthlyTotal = 0;
|
|---|
| 182 | $DbResult2 = $this->Database->query('SELECT `Service`.* '.
|
|---|
| 183 | 'FROM `ServiceCustomerRel` LEFT JOIN `Service` '.
|
|---|
| 184 | 'ON `Service`.`Id`=`ServiceCustomerRel`.`Service` '.
|
|---|
| 185 | 'WHERE (`ServiceCustomerRel`.`Customer`='.
|
|---|
| 186 | $Member['Id'].') AND (`ServiceCustomerRel`.`ChangeAction` IS NULL) ');
|
|---|
| 187 | while ($Service = $DbResult2->fetch_assoc())
|
|---|
| 188 | {
|
|---|
| 189 | $InvoiceItems[] = array('Description' => $Service['Name'], 'Price' => $Service['Price'],
|
|---|
| 190 | 'Quantity' => $Period['MonthCount'], 'VAT' => ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->GetVATByType($Service['VAT']));
|
|---|
| 191 | $MonthlyTotal += $Service['Price'];
|
|---|
| 192 | }
|
|---|
| 193 | $PayPerPeriod = $MonthlyTotal * $Period['MonthCount'];
|
|---|
| 194 | // We can't produce negative invoice except storno invoice.
|
|---|
| 195 | // TODO: In case of negative invoice it is not sufficient to reverse invoicing direction
|
|---|
| 196 | // Other subject should invoice only positive items. Negative items should be somehow removed.
|
|---|
| 197 | if ($MonthlyTotal >= 0)
|
|---|
| 198 | {
|
|---|
| 199 | $InvoiceGroupId = INVOICE_GROUP_OUT;
|
|---|
| 200 | } else
|
|---|
| 201 | {
|
|---|
| 202 | $InvoiceGroupId = INVOICE_GROUP_IN;
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | // Load invoice group
|
|---|
| 206 | $FinanceGroup = ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->GetFinanceGroupById($InvoiceGroupId, 'FinanceInvoiceGroup');
|
|---|
| 207 | foreach ($InvoiceItems as $Index => $Item)
|
|---|
| 208 | {
|
|---|
| 209 | $InvoiceItems[$Index]['Price'] = $Item['Price'] * $FinanceGroup['ValueSign'];
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | if ($PayPerPeriod != 0)
|
|---|
| 213 | {
|
|---|
| 214 | $TimePeriodText = date('j.n.Y', $Period['From']).' - '.date('j.n.Y', $Period['To']);
|
|---|
| 215 | $Output .= $TimePeriodText.': '.$MonthlyTotal.' * '.$Period['MonthCount'].' = '.$PayPerPeriod;
|
|---|
| 216 | $this->InsertInvoice($Member['Subject'], time(), time() + 3600 * 24 * INVOICE_DUE_DAYS,
|
|---|
| 217 | $InvoiceItems, $FinanceGroup, $Period['From'], $Period['To']);
|
|---|
| 218 |
|
|---|
| 219 | $Output .= $this->SendPaymentEmail($Member['Id']);
|
|---|
| 220 | }
|
|---|
| 221 | // Update last billing day
|
|---|
| 222 | $this->Database->update('Member', '`Id`='.$Member['Id'],
|
|---|
| 223 | array('BillingPeriodLastDate' => TimeToMysqlDateTime($Period['To'])));
|
|---|
| 224 | }
|
|---|
| 225 | $Output .= "\n";
|
|---|
| 226 | }
|
|---|
| 227 | return $Output;
|
|---|
| 228 | }
|
|---|
| 229 |
|
|---|
| 230 | function TableUpdateChanges(string $Table): void
|
|---|
| 231 | {
|
|---|
| 232 | $Time = time();
|
|---|
| 233 | $DbResult = $this->Database->select($Table, '*', '(`ChangeAction` IS NOT NULL) AND '.
|
|---|
| 234 | '(`ChangeTime` <= "'.TimeToMysqlDateTime($Time).'") ORDER BY `ChangeTime` ASC');
|
|---|
| 235 | while ($Service = $DbResult->fetch_assoc())
|
|---|
| 236 | {
|
|---|
| 237 | if ($Service['ChangeAction'] == 'add')
|
|---|
| 238 | {
|
|---|
| 239 | unset($Service['Id']);
|
|---|
| 240 | unset($Service['ChangeReplaceId']);
|
|---|
| 241 | unset($Service['ChangeAction']);
|
|---|
| 242 | unset($Service['ChangeTime']);
|
|---|
| 243 | $this->Database->insert($Table, $Service);
|
|---|
| 244 | } else
|
|---|
| 245 | if ($Service['ChangeAction'] == 'modify')
|
|---|
| 246 | {
|
|---|
| 247 | unset($Service['Id']);
|
|---|
| 248 | unset($Service['ChangeAction']);
|
|---|
| 249 | $ReplaceId = $Service['ChangeReplaceId'];
|
|---|
| 250 | unset($Service['ChangeReplaceId']);
|
|---|
| 251 | unset($Service['ChangeTime']);
|
|---|
| 252 | $this->Database->update($Table, '`Id`='.$ReplaceId, $Service);
|
|---|
| 253 | } else
|
|---|
| 254 | if ($Service['ChangeAction'] == 'delete')
|
|---|
| 255 | {
|
|---|
| 256 | $this->Database->delete($Table, '`Id`='.$Service['ReplaceId']);
|
|---|
| 257 | }
|
|---|
| 258 | }
|
|---|
| 259 | $this->Database->delete($Table, '(`ChangeAction` IS NOT NULL) AND (`ChangeTime` <= "'.TimeToMysqlDateTime($Time).'")');
|
|---|
| 260 | }
|
|---|
| 261 |
|
|---|
| 262 | function ProcessTableUpdates(): string
|
|---|
| 263 | {
|
|---|
| 264 | // Update customers
|
|---|
| 265 | $Output = 'Měním zákazníky...'."\n";
|
|---|
| 266 | $this->TableUpdateChanges('Member');
|
|---|
| 267 |
|
|---|
| 268 | // Update finance charge
|
|---|
| 269 | $Output = 'Měním aktuální parametry sítě...'."\n";
|
|---|
| 270 | $this->TableUpdateChanges('FinanceCharge');
|
|---|
| 271 |
|
|---|
| 272 | // Update services
|
|---|
| 273 | $Output .= 'Aktualizuji služby....'."\n";
|
|---|
| 274 | $this->TableUpdateChanges('Service');
|
|---|
| 275 |
|
|---|
| 276 | // Update customer service selections
|
|---|
| 277 | $Output .= 'Aktualizuji výběr služeb zákazníků....'."\n";
|
|---|
| 278 | $this->TableUpdateChanges('ServiceCustomerRel');
|
|---|
| 279 |
|
|---|
| 280 | return $Output;
|
|---|
| 281 | }
|
|---|
| 282 |
|
|---|
| 283 | function ProcessMonthlyPayment(): string
|
|---|
| 284 | {
|
|---|
| 285 | if (!ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('Finance', 'Manage')) return 'Nemáte oprávnění';
|
|---|
| 286 | $Output = '';
|
|---|
| 287 |
|
|---|
| 288 | $Output .= $this->ProcessTableUpdates();
|
|---|
| 289 |
|
|---|
| 290 | $Finance = &ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance;
|
|---|
| 291 | $Finance->LoadMonthParameters(0);
|
|---|
| 292 |
|
|---|
| 293 | // Načti poslední měsíční přehled a nastavení
|
|---|
| 294 | $DbResult = $this->Database->select('FinanceMonthlyOverall', '*', '1 ORDER BY `Date` DESC LIMIT 1');
|
|---|
| 295 | $Overall = $DbResult->fetch_array();
|
|---|
| 296 |
|
|---|
| 297 | $Output .= 'Datum: '.date('j.n.Y')."\n";
|
|---|
| 298 |
|
|---|
| 299 | $DateParts = explode('-', $Overall['Date']);
|
|---|
| 300 | $MonthLast = $DateParts[1];
|
|---|
| 301 | $YearLast = $DateParts[0];
|
|---|
| 302 | $MonthCurrent = date('m') + 0;
|
|---|
| 303 | $YearCurrent = date('Y') + 0;
|
|---|
| 304 |
|
|---|
| 305 | $Output .= $Finance->RecalculateMemberPayment();
|
|---|
| 306 |
|
|---|
| 307 | $DbResult = $this->Database->query('SELECT SUM(`Cash`) FROM `MemberPayment`');
|
|---|
| 308 | $Row = $DbResult->fetch_row();
|
|---|
| 309 | $TotalMemberCash = $Row[0];
|
|---|
| 310 | $Output .= 'Stav pokladny: Členové('.round($TotalMemberCash).')'."\n";
|
|---|
| 311 |
|
|---|
| 312 | $DbResult = $this->Database->query('SELECT SUM(`Product`.`Consumption`) AS `Consumption` FROM `StockSerialNumber` '.
|
|---|
| 313 | 'JOIN `Product` ON `StockSerialNumber`.`Product` = `Product`.`Id` WHERE (`StockSerialNumber`.`TimeElimination` IS NULL) ');
|
|---|
| 314 | $Row = $DbResult->fetch_row();
|
|---|
| 315 | $TotalConsumption = $Row[0];
|
|---|
| 316 | $TotalConsumptionCost = $Finance->W2Kc($TotalConsumption);
|
|---|
| 317 |
|
|---|
| 318 | $SpravaCelkem = $Finance->Sprava * $Finance->SpravaUsers;
|
|---|
| 319 | $Output .= 'Kontrola placení (Zaplaceno-Sprava-Internet): '.$Finance->TotalPaid.'-'.$SpravaCelkem.'-'.$Finance->Internet.'='.($Finance->TotalPaid - $SpravaCelkem - $Finance->Internet)."\n";
|
|---|
| 320 |
|
|---|
| 321 | // Zkontrolovat odečtení měsíčního poplatku
|
|---|
| 322 | $Output .= 'Kontrola odečtení poplatků: Poslední měsíc-'.$MonthLast.' Aktuální měsíc-'.$MonthCurrent."\n";
|
|---|
| 323 | if (($MonthCurrent != $MonthLast) or ($YearCurrent != $YearLast))
|
|---|
| 324 | {
|
|---|
| 325 | $Output .= 'Odečítám pravidelný poplatek...'."\n";
|
|---|
| 326 | $Output .= $this->ProduceInvoices();
|
|---|
| 327 |
|
|---|
| 328 | $Output .= 'Přidávám měsíční přehled...'."\n";
|
|---|
| 329 | $DbResult = $this->Database->query('SELECT * FROM `FinanceCharge` WHERE (`ChangeAction` IS NULL) LIMIT 1');
|
|---|
| 330 | $Charge = $DbResult->fetch_assoc();
|
|---|
| 331 | $this->Database->insert('FinanceMonthlyOverall', array('Date' => 'NOW()',
|
|---|
| 332 | 'Money' => $Finance->Internet, 'kWh' => $Finance->kWh,
|
|---|
| 333 | 'Administration' => $Finance->Sprava, 'AdministrationTotal' => $SpravaCelkem,
|
|---|
| 334 | 'ConsumptionTotal' => $TotalConsumptionCost, 'TotalPaid' => $Finance->TotalPaid,
|
|---|
| 335 | 'BaseTariffPrice' => $Charge['BaseTariffPrice'],
|
|---|
| 336 | 'TopTariffPrice' => $Charge['TopTariffPrice'], 'MemberCount' => $Finance->InternetUsers));
|
|---|
| 337 |
|
|---|
| 338 | $Finance->RecalculateMemberPayment();
|
|---|
| 339 |
|
|---|
| 340 | // Restart traffic shaping
|
|---|
| 341 | //$this->Database->update('NetworkConfiguration', 'Id = 3', array('Changed' => 1));
|
|---|
| 342 | //flush();
|
|---|
| 343 | //$this->GenerateBills();
|
|---|
| 344 | ModuleLog::Cast($this->System->GetModule('Log'))->NewRecord('Finance', 'ProcessMonthlyPayment', $Output);
|
|---|
| 345 | }
|
|---|
| 346 | $Output = str_replace("\n", '<br/>', $Output);
|
|---|
| 347 | return $Output;
|
|---|
| 348 | }
|
|---|
| 349 |
|
|---|
| 350 | function SendPaymentEmail(string $MemberId, string $FileId = ''): string
|
|---|
| 351 | {
|
|---|
| 352 | $Finance = &ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance;
|
|---|
| 353 | $Finance->LoadMonthParameters(0);
|
|---|
| 354 |
|
|---|
| 355 | if (!ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('Finance', 'Manage')) return 'Nemáte oprávnění';
|
|---|
| 356 | global $Config;
|
|---|
| 357 |
|
|---|
| 358 | $DbResult = $this->Database->select('Member', '*', '`Id`='.$MemberId);
|
|---|
| 359 | $Member = $DbResult->fetch_assoc();
|
|---|
| 360 |
|
|---|
| 361 | $DbResult = $this->Database->select('MemberPayment', '*', '`Member`='.$MemberId);
|
|---|
| 362 | $MemberPayment = $DbResult->fetch_assoc();
|
|---|
| 363 |
|
|---|
| 364 | $DbResult = $this->Database->select('Subject', 'Name', '`Id`='.$Member['Subject']);
|
|---|
| 365 | $Subject = $DbResult->fetch_assoc();
|
|---|
| 366 |
|
|---|
| 367 | $DbResult = $this->Database->select('User', '*', '`Id`='.$Member['ResponsibleUser']);
|
|---|
| 368 | $User = $DbResult->fetch_assoc();
|
|---|
| 369 |
|
|---|
| 370 | $DbResult = $this->Database->select('Subject', '*', '`Id`='.$Config['Finance']['MainSubjectId']);
|
|---|
| 371 | $MainSubject = $DbResult->fetch_assoc();
|
|---|
| 372 |
|
|---|
| 373 | $DbResult = $this->Database->select('Company', '*', '`Id`='.$Config['Finance']['MainCompanyId']);
|
|---|
| 374 | $MainCompany = $DbResult->fetch_assoc();
|
|---|
| 375 |
|
|---|
| 376 | $Period = $this->GetBillingPeriod($Member['BillingPeriod']);
|
|---|
| 377 |
|
|---|
| 378 | $DbResult = $this->Database->query('SELECT `FinanceBankAccount`.*, '.
|
|---|
| 379 | 'CONCAT(`FinanceBankAccount`.`Number`, "/", `FinanceBank`.`Code`) AS `NumberFull` FROM `FinanceBankAccount` '.
|
|---|
| 380 | 'JOIN `FinanceBank` ON `FinanceBank`.`Id`=`FinanceBankAccount`.`Bank` '.
|
|---|
| 381 | 'WHERE (`FinanceBankAccount`.`Subject`='.$Config['Finance']['MainSubjectId'].') '.
|
|---|
| 382 | 'AND (`FinanceBankAccount`.`Use`=1)');
|
|---|
| 383 | $MainSubjectAccount = $DbResult->fetch_assoc();
|
|---|
| 384 |
|
|---|
| 385 | if ($User['Email'] != '')
|
|---|
| 386 | {
|
|---|
| 387 | $Title = 'Pravidelné vyúčtování služeb '.$MainCompany['Name'];
|
|---|
| 388 | $Content = 'Dobrý den,<br/><br/>'.
|
|---|
| 389 | 'Zasíláme vyúčtování klienta <strong>'.$Subject['Name'].'</strong> zastoupeného uživatelem <strong>'.
|
|---|
| 390 | $User['Name'].'</strong> ke dni <strong>'.Core::Cast($this->System)->HumanDate(time()).'</strong>.<br/><br/>'."\n".
|
|---|
| 391 | 'Vaše aktuální služby: ';
|
|---|
| 392 | $DbResult = $this->Database->query('SELECT GROUP_CONCAT(`Service`.`Name`) AS `Name` FROM `ServiceCustomerRel` LEFT JOIN `Service` '.
|
|---|
| 393 | 'ON `Service`.`Id`=`ServiceCustomerRel`.`Service` WHERE (`ServiceCustomerRel`.`Customer`='.$Member['Id'].') '.
|
|---|
| 394 | 'AND (`ServiceCustomerRel`.`ChangeAction` IS NULL)');
|
|---|
| 395 | $Service = $DbResult->fetch_assoc();
|
|---|
| 396 | $Content .= '<strong>'.$Service['Name'].'</strong><br />'."\n".
|
|---|
| 397 | 'Vaše platební období: <strong>'.ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->BillingPeriods[$Member['BillingPeriod']]['Name'].'</strong><br />'."\n".
|
|---|
| 398 | 'Pravidelná platba za období: <strong>'.($MemberPayment['MonthlyTotal'] * $Period['MonthCount']).' Kč</strong><br />'."\n".
|
|---|
| 399 | 'Bankovní účet: <strong>'.$MainSubjectAccount['NumberFull'].'</strong><br/>'."\n".
|
|---|
| 400 | 'Variabilní symbol: <strong>'.$Member['Subject'].'</strong><br/>'."\n".
|
|---|
| 401 | 'Stav vašeho účtu: <strong>'.($MemberPayment['Cash'] - $MemberPayment['MonthlyTotal'] * $Period['MonthCount']).' Kč</strong><br /><br />'."\n";
|
|---|
| 402 | $Content .= 'Nové finanční operace:<br/>'.
|
|---|
| 403 | '<table style="margin-left: auto; margin-right: auto; border-style: solid; border-width: 1px; border-collapse: collapse;">'.
|
|---|
| 404 | '<tr><th style="border-style: solid; border-width: 1px; padding: 1px 5px 1px 5px; text-align: center; font-weight: bold;">Čas</th>'.
|
|---|
| 405 | '<th style="border-style: solid; border-width: 1px; padding: 1px 5px 1px 5px; text-align: center; font-weight: bold;">Popis</th>'.
|
|---|
| 406 | '<th style="border-style: solid; border-width: 1px; padding: 1px 5px 1px 5px; text-align: center; font-weight: bold;">Částka [Kč]</th></tr>'."\n";
|
|---|
| 407 | if ($Member['PaymentEmailTime'] <> 'NULL')
|
|---|
| 408 | {
|
|---|
| 409 | $Where = ' WHERE (`T1`.`Time` > "'.$Member['PaymentEmailTime'].'")';
|
|---|
| 410 | } else
|
|---|
| 411 | {
|
|---|
| 412 | $Where = '';
|
|---|
| 413 | }
|
|---|
| 414 | $DbResult = $this->Database->query('SELECT T1.* FROM ((SELECT `Text`, `Time`, `Value`, `File` FROM `FinanceOperation` WHERE (`Subject`='.$Member['Subject'].')) UNION ALL '.
|
|---|
| 415 | '(SELECT (SELECT GROUP_CONCAT(`Description` SEPARATOR ", ") FROM `FinanceInvoiceItem` '.
|
|---|
| 416 | 'WHERE `FinanceInvoiceItem`.`FinanceInvoice` = `FinanceInvoice`.`Id`) AS `Text`, '.
|
|---|
| 417 | '`Time`, -`Value`, `File` FROM `FinanceInvoice` WHERE (`Subject`='.$Member['Subject'].')) ORDER BY `Time` DESC) AS `T1`'.$Where);
|
|---|
| 418 | while ($DbRow = $DbResult->fetch_assoc())
|
|---|
| 419 | {
|
|---|
| 420 | $Text = $DbRow['Text'];
|
|---|
| 421 | $Content .= '<tr><td style="border-style: solid; border-width: 1px; padding: 1px 5px 1px 5px; text-align: center;">'.HumanDate($DbRow['Time']).'</td>'.
|
|---|
| 422 | '<td style="border-style: solid; border-width: 1px; padding: 1px 5px 1px 5px; text-align: center;">'.$Text.'</td>'.
|
|---|
| 423 | '<td style="border-style: solid; border-width: 1px; padding: 1px 5px 1px 5px; text-align: center;">'.$DbRow['Value'].'</td></tr>'."\n";
|
|---|
| 424 | }
|
|---|
| 425 | $Content .= '</table><br />'."\n".
|
|---|
| 426 | 'Pro aktuální informace, prohlížení elektronických dokladů a možnost změny údajů se prosím přihlaste na stránkách '.
|
|---|
| 427 | '<a href="https://'.$Config['Web']['Host'].$Config['Web']['RootFolder'].'">https://'.
|
|---|
| 428 | $Config['Web']['Host'].$Config['Web']['RootFolder'].'</a>.<br/><br/>'."\n";
|
|---|
| 429 |
|
|---|
| 430 | $Content .= '<br/>Tento email je generován automaticky. V případě zjištění nesrovnalostí prosím napište zpět.';
|
|---|
| 431 |
|
|---|
| 432 | $Content .= '<br/><br/>S pozdravem,<br/>'.$MainCompany['Name'].'<br/><a href="'.$MainSubject['WWW'].'">'.
|
|---|
| 433 | str_replace(array('https:', '/'), '', $MainSubject['WWW']).'</a>';
|
|---|
| 434 |
|
|---|
| 435 | ModuleEmailQueue::Cast($this->System->GetModule('EmailQueue'))->AddItem($User['Name'].' <'.$User['Email'].'>', $Title, $Content,
|
|---|
| 436 | $Config['Web']['Admin'].' <'.$Config['Web']['AdminEmail'].'>');
|
|---|
| 437 | $this->Database->update('Member', 'Id='.$Member['Id'], array('PaymentEmailTime' => 'NOW()'));
|
|---|
| 438 | $Output = '';
|
|---|
| 439 | } else $Output = 'Uživatel '.$User['Name'].' nemá email.';
|
|---|
| 440 | return $Output;
|
|---|
| 441 | }
|
|---|
| 442 |
|
|---|
| 443 | function GenerateInvoice(string $Where): string
|
|---|
| 444 | {
|
|---|
| 445 | $DirectoryId = ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->DirectoryId;
|
|---|
| 446 | $Output = '';
|
|---|
| 447 | $DbResult = $this->Database->query('SELECT * FROM `FinanceInvoice` WHERE (`BillCode` <> "") '.
|
|---|
| 448 | 'AND (`Value` != 0) AND (`Generate` = 1)'.$Where);
|
|---|
| 449 | while ($Row = $DbResult->fetch_assoc())
|
|---|
| 450 | {
|
|---|
| 451 | if ($Row['File'] == null)
|
|---|
| 452 | {
|
|---|
| 453 | $this->Database->insert('File', array('Name' => '', 'Size' => 0, 'Directory' => $DirectoryId, 'Time' => 'NOW()',
|
|---|
| 454 | 'Hash' => 'SHA1(CONCAT(Id,Name,Size,Time))'));
|
|---|
| 455 | $FileId = $this->Database->insert_id;
|
|---|
| 456 | } else $FileId = $Row['File'];
|
|---|
| 457 | $FileName = 'doklad-'.$FileId.'.pdf';
|
|---|
| 458 | $Bill = new BillInvoice($this->System);
|
|---|
| 459 | $Bill->InvoiceId = $Row['Id'];
|
|---|
| 460 | $FullFileName = ModuleFile::Cast($this->System->GetModule('File'))->File->GetDir($DirectoryId).$FileName;
|
|---|
| 461 | $Bill->SaveToFile($FullFileName);
|
|---|
| 462 | if (file_exists($FullFileName))
|
|---|
| 463 | {
|
|---|
| 464 | $this->Database->update('File', 'Id='.$FileId, array('Name' => $FileName, 'Size' => filesize($FullFileName), 'Hash' => 'SHA1(CONCAT(Id,Name,Size,Time))'));
|
|---|
| 465 | $this->Database->update('FinanceInvoice', 'Id='.$Row['Id'], array('File' => $FileId));
|
|---|
| 466 | $Output .= 'Faktura '.$Row['Id'].' vygenerována do souboru '.$FileName.'<br/>'."\n";
|
|---|
| 467 | } else $Output .= 'Soubor "'.$FullFileName.'" se nepodařilo uložit.';
|
|---|
| 468 | }
|
|---|
| 469 | return $Output;
|
|---|
| 470 | }
|
|---|
| 471 |
|
|---|
| 472 | function GenerateOperation(string $Where): string
|
|---|
| 473 | {
|
|---|
| 474 | $DirectoryId = ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance->DirectoryId;
|
|---|
| 475 | $Output = '';
|
|---|
| 476 | $DbResult = $this->Database->query('SELECT * FROM `FinanceOperation` WHERE (`BillCode` <> "") '.
|
|---|
| 477 | 'AND (`Value` != 0) AND (`Generate` = 1)'.$Where);
|
|---|
| 478 | while ($Row = $DbResult->fetch_assoc())
|
|---|
| 479 | {
|
|---|
| 480 | if ($Row['File'] == null)
|
|---|
| 481 | {
|
|---|
| 482 | $DbResult2 = $this->Database->insert('File', array('Name' => '', 'Size' => 0,
|
|---|
| 483 | 'Directory' => $DirectoryId, 'Time' => 'NOW()', 'Hash' => 'SHA1(CONCAT(Id,Name,Size,Time))'));
|
|---|
| 484 | $FileId = $this->Database->insert_id;
|
|---|
| 485 | } else $FileId = $Row['File'];
|
|---|
| 486 | $FileName = 'doklad2-'.$FileId.'.pdf';
|
|---|
| 487 | $Bill = new BillOperation($this->System);
|
|---|
| 488 | $Bill->OperationId = $Row['Id'];
|
|---|
| 489 | $FullFileName = ModuleFile::Cast($this->System->GetModule('File'))->File->GetDir($DirectoryId).$FileName;
|
|---|
| 490 | $Bill->SaveToFile($FullFileName);
|
|---|
| 491 | if (file_exists($FullFileName))
|
|---|
| 492 | {
|
|---|
| 493 | $this->Database->update('File', 'Id='.$FileId, array('Name' => $FileName, 'Size' => filesize($FullFileName), 'Hash' => 'SHA1(CONCAT(Id,Name,Size,Time))'));
|
|---|
| 494 | $this->Database->update('FinanceOperation', 'Id='.$Row['Id'], array('File' => $FileId));
|
|---|
| 495 | $Output .= 'Doklad pro platbu '.$Row['Id'].' vygenerován do souboru '.$FileName.'<br/>'."\n";
|
|---|
| 496 | } else $Output .= 'Soubor "'.$FullFileName.'" se nepodařilo uložit.';
|
|---|
| 497 | }
|
|---|
| 498 | return $Output;
|
|---|
| 499 | }
|
|---|
| 500 |
|
|---|
| 501 | function GenerateBills(): string
|
|---|
| 502 | {
|
|---|
| 503 | $Output = '';
|
|---|
| 504 | // Generate PDF files for new invoices and operations
|
|---|
| 505 | $Output .= $this->GenerateInvoice(' AND (`File` IS NULL)');
|
|---|
| 506 | $Output .= $this->GenerateOperation(' AND (`File` IS NULL)');
|
|---|
| 507 | return $Output;
|
|---|
| 508 | }
|
|---|
| 509 | }
|
|---|