source: trunk/Modules/Contract/Contract.php

Last change on this file was 958, checked in by chronos, 16 months ago
  • Fixed: Numeric check for input values.
File size: 17.7 KB
Line 
1<?php
2
3class ModuleContract extends Module
4{
5 public int $DirectoryId;
6
7 function __construct(System $System)
8 {
9 parent::__construct($System);
10 $this->Name = 'Contract';
11 $this->Version = '1.0';
12 $this->Creator = 'Chronos';
13 $this->License = 'GNU/GPLv3';
14 $this->Description = 'Contract documents management';
15 $this->Dependencies = array(ModuleDocument::GetName(), ModuleSubject::GetName(), ModuleFile::GetName(), ModuleFinance::GetName());
16 $this->Models = array(Contract::GetClassName());
17
18 $this->DirectoryId = 0;
19 }
20
21 function DoStart(): void
22 {
23 $this->DirectoryId = Core::Cast($this->System)->Config['Contract']['DirectoryId'];
24 $this->System->RegisterPage(['smlouvy', 'generovat'], 'PageContractGenerate');
25 Core::Cast($this->System)->FormManager->RegisterClass('Contract', array(
26 'Title' => 'Smlouvy',
27 'Table' => 'Contract',
28 'Items' => array(
29 'DocumentLine' => array('Type' => 'TDocumentLine', 'Caption' => 'Dokladová řada', 'Default' => ''),
30 'BillCode' => array('Type' => 'TDocumentLineCode', 'Caption' => 'Kód', 'Default' => '', 'Null' => true),
31 'Subject' => array('Type' => 'TSubject', 'Caption' => 'Subjekt', 'Default' => ''),
32 'ValidFrom' => array('Type' => 'Date', 'Caption' => 'Platnost od', 'Default' => ''),
33 'ValidTo' => array('Type' => 'Date', 'Caption' => 'Platnost do', 'Default' => '', 'Null' => true),
34 'File' => array('Type' => 'TFile', 'Caption' => 'Soubor', 'Default' => '', 'Null' => true),
35 'Generate' => array('Type' => 'Boolean', 'Caption' => 'Generovat', 'Default' => ''),
36 'EmployeeSalaries' => array('Type' => 'TEmployeeSalaryListContract', 'Caption' => 'Výplaty zaměstnanců', 'Default' => ''),
37 'Customers' => array('Type' => 'TCustomerListContract', 'Caption' => 'Zákazníci', 'Default' => ''),
38 ),
39 'BeforeInsert' => array($this, 'BeforeInsertContract'),
40 'ItemActions' => array(
41 array('Caption' => 'Generovat', 'URL' => '/smlouvy/generovat/?i=#RowId'),
42 )
43 ));
44 Core::Cast($this->System)->FormManager->RegisterFormType('TContract', array(
45 'Type' => 'Reference',
46 'Table' => 'Contract',
47 'Id' => 'Id',
48 'Name' => '(SELECT `DocumentLineCode`.`Name` FROM `DocumentLineCode` WHERE `Id`=`Contract`.`BillCode`)',
49 'Filter' => '1',
50 ));
51 }
52
53 function BeforeInsertContract(Form $Form): array
54 {
55 if (array_key_exists('Time', $Form->Values)) $Year = date("Y", $Form->Values['Time']);
56 else $Year = date("Y", $Form->Values['ValidFrom']);
57 $Form->Values['BillCode'] = ModuleDocument::Cast($this->System->GetModule('Document'))->GetNextDocumentLineNumberId($Form->Values['DocumentLine'], $Year);
58 return $Form->Values;
59 }
60
61 static function Cast(Module $Module): ModuleContract
62 {
63 if ($Module instanceof ModuleContract)
64 {
65 return $Module;
66 }
67 throw new Exception('Expected ModuleContract type but '.gettype($Module));
68 }
69}
70
71class PageContractGenerate extends Page
72{
73 function __construct(System $System)
74 {
75 parent::__construct($System);
76 $this->Title = 'Generování smlouvy';
77 $this->ParentClass = 'PagePortal';
78 }
79
80 function GenerateContract($Where = '')
81 {
82 $DirectoryId = ModuleContract::Cast($this->System->GetModule('Contract'))->DirectoryId;
83 $Output = '';
84 $DbResult = $this->Database->query('SELECT * FROM `Contract` WHERE (`BillCode` <> "") '.
85 'AND (`ValidFrom` IS NOT NULL) AND (`Generate` = 1)'.$Where);
86 while ($Row = $DbResult->fetch_assoc())
87 {
88 if ($Row['File'] == null)
89 {
90 $this->Database->insert('File', array('Name' => '', 'Size' => 0, 'Directory' => $DirectoryId, 'Time' => 'NOW()',
91 'Hash' => 'SHA1(CONCAT(Id,Name,Size,Time))'));
92 $FileId = $this->Database->insert_id;
93 } else $FileId = $Row['File'];
94 $FileName = 'smlouva-'.$FileId.'.pdf';
95 $Bill = new BillContract($this->System);
96 $Bill->ContractId = $Row['Id'];
97 $FullFileName = ModuleFile::Cast($this->System->GetModule('File'))->File->GetDir($DirectoryId).$FileName;
98 $Bill->SaveToFile($FullFileName);
99 if (file_exists($FullFileName))
100 {
101 $this->Database->update('File', 'Id='.$FileId, array('Name' => $FileName, 'Size' => filesize($FullFileName), 'Hash' => 'SHA1(CONCAT(Id,Name,Size,Time))'));
102 $this->Database->update('Contract', 'Id='.$Row['Id'], array('File' => $FileId));
103 $Output .= 'Smlouva '.$Row['Id'].' vygenerována do souboru '.$FileName.'<br/>'."\n";
104 } else $Output .= 'Soubor "'.$FullFileName.'" se nepodařilo uložit.';
105 }
106 return $Output;
107 }
108
109 function Show(): string
110 {
111 if (array_key_exists('i', $_GET) and is_numeric($_GET['i']))
112 {
113 $Output = $this->GenerateContract(' AND (Id='.($_GET['i'] * 1).')');
114 } else $Output = 'Missing contract id.';
115 return $Output;
116 }
117}
118
119class BillContract extends Pdf
120{
121 public string $ContractId;
122
123 function GenerateHTML(): string
124 {
125 $this->BorderTop = '0cm';
126 $this->BorderLeft = '1cm';
127 $this->BorderRight = '1cm';
128 $this->BorderBottom = '0cm';
129 $this->FontSize = 10;
130
131 $DbResult = $this->Database->select('Subject', '*', '`Id`='.Core::Cast($this->System)->Config['Finance']['MainSubjectId']);
132 if ($DbResult->num_rows > 0)
133 {
134 $Supplier = $DbResult->fetch_assoc();
135 } else die('MainSubjectId not found in Subjects.');
136
137 $DbResult = $this->Database->query('SELECT * FROM `Contract` WHERE `Id`='.$this->ContractId);
138 if ($DbResult->num_rows > 0)
139 {
140 $Contract = $DbResult->fetch_array();
141 $DbResult = $this->Database->query('SELECT * FROM `Subject` WHERE `Id`='.$Contract['Subject']);
142 if ($DbResult->num_rows > 0)
143 {
144 $Subject = $DbResult->fetch_assoc();
145 } else die('Customer Subject not found.');
146 } else die('Contract not found.');
147
148 $DbResult = $this->Database->select('DocumentLineCode', '*', '`Id`='.$Contract['BillCode']);
149 if ($DbResult->num_rows > 0)
150 {
151 $SupplierBillCode = $DbResult->fetch_assoc();
152 } else die('BillCode not found.');
153 $ContractCode = $SupplierBillCode['Name'];
154
155 $DbResult = $this->Database->select('Member', '*', '`Subject`='.$Contract['Subject']);
156 if ($DbResult->num_rows > 0)
157 {
158 $Customer = $DbResult->fetch_assoc();
159 } else die('Customer not found.');
160
161 $PrefixMultiplier = new PrefixMultiplier();
162 $ServiceType = '';
163 $Price = 0;
164 $MaxSpeed = '';
165 $MinSpeed = '';
166 $DbResult = $this->Database->query('SELECT * FROM ServiceCustomerRel '.
167 'LEFT JOIN Service ON Service.Id=ServiceCustomerRel.Service '.
168 'WHERE `ServiceCustomerRel`.`Customer`='.$Customer['Id'].' ');
169 if ($DbResult->num_rows > 0)
170 {
171 while ($Service = $DbResult->fetch_assoc())
172 {
173 if ($ServiceType != '') $ServiceType .= ', ';
174 $ServiceType .= $Service['Name'];
175 $Price += $Service['Price'];
176 if ($Service['InternetSpeedMax'] != 0)
177 $MaxSpeed = $PrefixMultiplier->Add($Service['InternetSpeedMax'], 'bit/s');
178 if ($Service['InternetSpeedMin'] != 0)
179 $MinSpeed = $PrefixMultiplier->Add($Service['InternetSpeedMin'], 'bit/s');
180 }
181 }
182
183 $DbResult = $this->Database->query('SELECT NetworkInterface.LocalIP, NetworkInterface.MAC FROM NetworkDevice '.
184 'LEFT JOIN NetworkInterface ON NetworkInterface.Device=NetworkDevice.Id '.
185 'WHERE `NetworkDevice`.`Member`='.$Customer['Id'].' ');
186 if ($DbResult->num_rows > 0)
187 {
188 $NetworkInterface = $DbResult->fetch_assoc();
189 $IpAddress = $NetworkInterface['LocalIP'];
190 $MacAddress = $NetworkInterface['MAC'];
191
192 $DbResult = $this->Database->query('SELECT * FROM NetworkSubnet '.
193 'WHERE CompareNetworkPrefix(INET_ATON("'.$IpAddress.'"), INET_ATON(`AddressRange`), `Mask`)');
194 if ($DbResult->num_rows > 0)
195 {
196 $Subnet = $DbResult->fetch_assoc();
197 $DefaultGateway = $Subnet['Gateway'];
198 $NetworkAddressIPv4 = new NetworkAddressIPv4();
199 $NetworkAddressIPv4->Prefix = $Subnet['Mask'];
200 $NetworkAddressIPv4->Address = $NetworkAddressIPv4->GetNetMask();
201 $NetMask = $NetworkAddressIPv4->AddressToString();
202 } else die('Subnet not found.');
203 $Interface = 'Ethernet';
204 $PrimaryDNS = '10.145.64.8';
205 } else
206 {
207 $IpAddress = '';
208 $MacAddress = '';
209 $DefaultGateway = '';
210 $NetMask = '';
211 $Interface = '';
212 $PrimaryDNS = '';
213 }
214
215 $VarSymbol = $Subject['Id'];
216 $DbResult = $this->Database->query('SELECT FinanceBankAccount.*, CONCAT(FinanceBankAccount.Number, "/", FinanceBank.Code) AS NumberFull FROM FinanceBankAccount '.
217 'JOIN FinanceBank ON FinanceBank.Id=FinanceBankAccount.Bank '.
218 'WHERE (FinanceBankAccount.`Subject`='.Core::Cast($this->System)->Config['Finance']['MainSubjectId'].') AND (FinanceBankAccount.`Use`=1)');
219 if ($DbResult->num_rows > 0)
220 {
221 $SupplierBankAccount = $DbResult->fetch_assoc();
222 } else die('Bank account not found.');
223
224 $DbResult = $this->Database->select('FinanceBillingPeriod', '*', 'Id='.$Customer['BillingPeriod']);
225 if ($DbResult->num_rows > 0)
226 {
227 $BillingPeriod = $DbResult->fetch_assoc();
228 } else die('BillingPeriod not found.');
229 $PaymentPeriod = $BillingPeriod['Name'];
230
231 $BankAccount = $SupplierBankAccount['NumberFull'];
232
233 $DbResult = $this->Database->select('Member', '*', '`Subject`='.Core::Cast($this->System)->Config['Finance']['MainSubjectId']);
234 if ($DbResult->num_rows > 0)
235 {
236 $SupplierMember = $DbResult->fetch_assoc();
237 } else die('Customer not found.');
238
239 $DbResult = $this->Database->query('SELECT Contact.Value AS Phone FROM User '.
240 'LEFT JOIN Contact ON Contact.User=User.ID AND Contact.Category=1 '.
241 'WHERE User.Id='.$SupplierMember['ResponsibleUser'].' ORDER BY `Contact`.`Receive` DESC');
242 if ($DbResult->num_rows > 0)
243 {
244 $SupplierUser = $DbResult->fetch_assoc();
245 $SupplierPhone = $SupplierUser['Phone'];
246 } else $SupplierPhone = '';
247
248 $DbResult = $this->Database->query('SELECT Contact.Value AS Phone FROM User '.
249 'LEFT JOIN Contact ON Contact.User=User.ID AND Contact.Category=1 '.
250 'WHERE User.Id='.$Customer['ResponsibleUser'].' ORDER BY `Contact`.`Receive` DESC');
251 if ($DbResult->num_rows > 0)
252 {
253 $CustomerUser = $DbResult->fetch_assoc();
254 $CustomerPhone = $CustomerUser['Phone'];
255 if ($CustomerPhone == null) $CustomerPhone = '';
256 } else $CustomerPhone = '';
257
258 $DbResult = $this->Database->query('SELECT Email, Contact.Value AS ContactEmail FROM User '.
259 'LEFT JOIN Contact ON Contact.User=User.ID AND Contact.Category=4 '.
260 'WHERE User.Id='.$Customer['ResponsibleUser'].' ORDER BY `Contact`.`Receive` DESC');
261 if ($DbResult->num_rows > 0)
262 {
263 $CustomerUser = $DbResult->fetch_assoc();
264 $CustomerEmail = $CustomerUser['Email'];
265 if ($CustomerEmail == null)
266 {
267 $CustomerEmail = $CustomerUser['ContactEmail'];
268 if ($CustomerEmail == null) $CustomerEmail = '';
269 }
270 } else $CustomerEmail = '';
271
272 $SupplierName = $Supplier['Name'];
273 $SupplierStreet = $Supplier['AddressStreet'];
274 $SupplierTown = $Supplier['AddressTown'];
275 $SupplierPsc = $Supplier['AddressPSC'];
276 $SupplierIC = $Supplier['IC'];
277 if ($Supplier['PayVAT'] == 1) $SupplierDIC = 'plátce DPH';
278 else $SupplierDIC = 'neplátce DPH';
279
280 $Web = '<a href="'.$Supplier['WWW'].'">'.$this->SimplifiedLink($Supplier['WWW']).'</a>';
281
282 $CustomerName = $Subject['Name'];
283 $CustomerStreet = $Subject['AddressStreet'];
284 $CustomerTown = $Subject['AddressTown'];
285 $CustomerPsc = $Subject['AddressPSC'];
286 $CustomerIC = $Subject['IC'];
287 $CustomerDIC = $Subject['DIC'];
288 $CustomerPhone = $CustomerPhone;
289 $CustomerEmail = $CustomerEmail;
290
291 $SignDate = HumanDate($Contract['ValidFrom']);
292
293 $Output = '<html>
294 <head></head>
295 <body><table width="100%"><tr><td colspan="2">'.
296 '<font size="6"><div align="center">Smlova o připojení k internetu a poskytování datových služeb</font></div>'.
297 '<font size="3"><div align="center">Číslo: '.$ContractCode.'</font></div>'.
298 '</td></tr>'.
299 '</table>'.
300 '<br>'.
301 '<table width="100%">'.
302 '<tr><th width="25%">Poskytovatel:</td><td width="25%"></td><th width="25%">Odběratel:</th><td width="25%"></td></tr>'.
303 '<tr><td>'.NotBlank($SupplierName).'</td><td></td><td>'.NotBlank($CustomerName).'</td><td></td></tr>'.
304 '<tr><td>'.NotBlank($SupplierStreet).'</td><td></td><td>'.NotBlank($CustomerStreet).'</td><td></td></tr>'.
305 '<tr><td>'.NotBlank($SupplierTown).'</td><td></td><td>'.NotBlank($CustomerTown).'</td><td></td></tr>'.
306 '<tr><td>'.NotBlank($SupplierPsc).'</td><td></td><td>'.NotBlank($CustomerPsc).'</td><td></td></tr>'.
307 '<tr><td colspan="4">&nbsp;</td></tr>'.
308 '<tr><td>IČ:</td><td>'.NotBlank($SupplierIC).'</td><td>Telefon:</td><td>'.NotBlank($CustomerPhone).'</td></tr>'.
309 '<tr><td>DIČ:</td><td>'.NotBlank($SupplierDIC).'</td><td>E-mail:</td><td>'.NotBlank($CustomerEmail).'</td></tr>'.
310 '<tr><td>Telefon:</td><td>'.NotBlank($SupplierPhone).'</td><td>RČ/IČ:</td><td>'.NotBlank($CustomerIC).'</td></tr>'.
311 '<tr><td>Web:</td><td>'.NotBlank($Web).'</td><td>OP/DIČ:</td><td>'.NotBlank($CustomerDIC).'</td></tr>'.
312 '<tr><td>Bank. spojení:</td><td>'.NotBlank($BankAccount).'</td><td>Přípojné místo:</td><td></td></tr>'.
313 '</table>'.
314 '<br/>'.
315 '<strong>I. Předmět smlouvy:</strong><br/>'.
316 'Smlouva se uzavírá mezi Poskytovatelem a Odběratelem a předmětem smlouvy je poskytování datových služeb a připojení k síti internet, umožňující Odběrateli odebírat v koncovém bodě za úplatu internetovou konektivitu prostřednictvím telekomunikační sítě Poskytovatele. Odběratel se zavazuje za tyto služby Poskytovateli platit cenu ve výši a pravidelných intervalech uvedených v této smlouvě. Smlouva se sjednává na dobu neurčitou.<br/>'.
317 '<br/>'.
318 '<strong>II. Poskytované služby:</strong><br/>'.
319 '<table width="100%" border="1">'.
320 '<tr><td width="50%">Zvolené služby:</td><td>'.NotBlank($ServiceType).'</td></tr>'.
321 '</table>'.
322 '<br/>'.
323 '<table width="100%" border="1">'.
324 '<tr><th colspan="4" align="center">Technické specifikace služby</th></tr>'.
325 '<tr><td width="25%">Max. rychlost:</td><td width="25%">'.NotBlank($MaxSpeed).'</td><td width="25%">IP adresa:</td><td width="25%">'.NotBlank($IpAddress).'</td></tr>'.
326 '<tr><td>Min. rychlost:</td><td>'.NotBlank($MinSpeed).'</td><td>Maska podsítě:</td><td>'.NotBlank($NetMask).'</td></tr>'.
327 '<tr><td>MAC adresa:</td><td>'.NotBlank($MacAddress).'</td><td>Výchozí brána:</td><td>'.NotBlank($DefaultGateway).'</td></tr>'.
328 '<tr><td>Předávací rozhraní:</td><td>'.NotBlank($Interface).'</td><td>Primární DNS:</td><td>'.NotBlank($PrimaryDNS).'</td></tr>'.
329 '</table>'.
330 '<br/>'.
331 '<strong>III. Cena a platební podmínky:</strong><br/>'.
332 'Poplatky a pravidelné platby budou na základě této smlouvy hrazeny Odběratelem na bankovní účet Poskytovatele bankovním převodem, nebo složenkou, v uvedené výši a s uvedenou frekvencí. Jako VS bude uvedeno přidělené číslo. V případě prodlení s platbou mohou být uplatněny sankce, či služba pozastavena, nebo zrušena (dle Ceníku a Všeobecných smluvních podmínek).<br/>'.
333 '<table width="100%">'.
334 '<tr><td width="25%">Cena služeb:</td><td width="25%">'.NotBlank($Price).' Kč</td><td width="25%">Číslo účtu:</td><td width="25%">'.NotBlank($BankAccount).'</td></tr>'.
335 '<tr><td>Pronájem zařízení:</td><td>0 Kč</td><td>Variabilní symbol:</td><td>'.NotBlank($VarSymbol).'</td></tr>'.
336 '<tr><td>Frekvence platby:</td><td>'.NotBlank($PaymentPeriod).'</td><td></td><td></td></tr>'.
337 '<tr><td>První platba:</td><td></td><td></td><td></td></tr>'.
338 '<tr><td>Splatnost:</td><td>do 21. dne uvedeného měsíce</td><td></td><td></td></tr>'.
339 '</table>'.
340 '<br/>'.
341 '<strong>IV. Závěrečná ustanovení:</strong><br/>'.
342 'Odběratel svým podpisem stvrzuje, že se seznámil a souhlasí se Všeobecnými smluvními podmínkami, aktuálním Ceníkem Poskytovatele a výše uvedenými skutečnostmi, které tvoří součást této Smlouvy. Dále stvrzuje, že souhlasí s provedením instalace a umístěním přijímacího zařízení a kabeláže a nemá proti nim námitky, příp., že vlastní veškerá příslušná povolení a souhlas s jejich umístěním. Smlouva je vyhotovena ve dvou provedeních, kdy Odběratel i Poskytovatel obdrží po jedné. Aktivace služby začíná dnem podpisu této Smlouvy. Výpovědní lhůta je 30 dnů. Případné změny této Smlouvy vyžadují formy vzájemně oběma stranami podepsaného dodatku.<br/>'.
343 '<br/>'.
344 '<table width="100%">'.
345 '<tr><td width="20%" aling="left">Ve Zděchově</td><td width="20%">dne '.NotBlank($SignDate).'</td></tr>'.
346 '</table>'.
347 '<br/><br/><br/><br/>'.
348 '<table width="100%">'.
349 '<tr><td width="50%" align="center">odběratel</td><td width="50%" align="center">dodavatel</td></tr>'.
350 '</table>'.
351 '</td></tr>'.
352 '</table>'.
353 '</body></html>';
354 return $Output;
355 }
356
357 function SimplifiedLink(string $Link): string
358 {
359 if (substr($Link, 0, 8) == 'https://') $Link = substr($Link, 8);
360 if (substr($Link, 0, 7) == 'http://') $Link = substr($Link, 7);
361 return $Link;
362 }
363}
364
365class Contract extends Model
366{
367 static function GetModelDesc(): ModelDesc
368 {
369 $Desc = new ModelDesc(self::GetClassName());
370 $Desc->AddReference('DocumentLine', DocumentLine::GetClassName());
371 $Desc->AddReference('BillCode', DocumentLineCode::GetClassName());
372 $Desc->AddReference('Subject', Subject::GetClassName());
373 $Desc->AddDate('ValidFrom');
374 $Desc->AddDate('ValidTo');
375 $Desc->AddReference('File', File::GetClassName());
376 return $Desc;
377 }
378}
Note: See TracBrowser for help on using the repository browser.