PageRenderTime 32ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/models/Invoice.php

https://github.com/balupton/balphp
PHP | 687 lines | 330 code | 127 blank | 230 comment | 24 complexity | ce2b2e024b348571858d97072518dbb6 MD5 | raw file
  1. <?php
  2. /**
  3. * User
  4. *
  5. * This class has been auto-generated by the Doctrine ORM Framework
  6. *
  7. * @package ##PACKAGE##
  8. * @subpackage ##SUBPACKAGE##
  9. * @author ##NAME## <##EMAIL##>
  10. * @version SVN: $Id: Builder.php 6508 2009-10-14 06:28:49Z jwage $
  11. */
  12. class Bal_Invoice extends Base_Bal_Invoice
  13. {
  14. /**
  15. * Apply accessors and modifiers
  16. * @return
  17. */
  18. public function setUp ( ) {
  19. parent::setUp();
  20. }
  21. /**
  22. * Create a Invoice from a template
  23. * @param string $template
  24. * @param array $data [optiona]
  25. * @return Invoice
  26. */
  27. public static function createFromTemplate ( $template, array $data = array() ) {
  28. # Prepare
  29. $Connection = Bal_App::getDataConnection();
  30. $Invoice = null;
  31. # Wrap
  32. try {
  33. # Start
  34. $Connection->beginTransaction();
  35. # Prepare Invoice
  36. $Invoice = new Invoice();
  37. # Template Invoice
  38. $Invoice->useTemplate($template, $data);
  39. # Save Invoice
  40. $Invoice->save();
  41. # Generate File
  42. $Invoice->generateFile();
  43. $Invoice->save();
  44. # Done
  45. $Connection->commit();
  46. }
  47. catch ( Exception $Exception ) {
  48. # Revert
  49. $Connection->rollback();
  50. # Log the Event and Continue
  51. $Exceptor = new Bal_Exceptor($Exception);
  52. $Exceptor->log();
  53. }
  54. # Done
  55. return $Invoice;
  56. }
  57. /**
  58. * Shortcut Message Creation via Codes
  59. * @return string
  60. */
  61. public function useTemplate ( $template, array $data = array() ) {
  62. # Prepare
  63. $Locale = Bal_App::getLocale();
  64. $Invoice = $this;
  65. # Merge Data
  66. if ( !empty($data) ) {
  67. foreach ( $data as $key => $value )
  68. $Invoice->set($key, $value);
  69. }
  70. # Apply Config
  71. $config = Bal_App::getConfig('invoice', array());
  72. $this->config = $config;
  73. # Apply Currency
  74. $this->currency_code = Bal_App::getConfig('locale.currency', 'AUD');
  75. # Apply Template
  76. $this->_set('template', $template, false);
  77. # Handle Template
  78. $function = '_template'.magic_function($template);
  79. if ( method_exists($this, $function) ) {
  80. $this->$function();
  81. }
  82. # Chain
  83. return $Invoice;
  84. }
  85. protected function _templateUserInvoice ( ) {
  86. # All properties are manually set
  87. # Chain
  88. return $this;
  89. }
  90. /**
  91. * Backup our Invoice into the back table
  92. * @throws Doctrine_Exception
  93. * @return InvoiceDataBackup
  94. */
  95. public function backup ( ) {
  96. # Check
  97. if ( !$this->isValid() ) {
  98. throw new Doctrine_Exception('Cannot backup an invalid model');
  99. }
  100. return;
  101. # Prepare
  102. $Invoice = $this;
  103. $invoice = $Invoice->toArray(true);
  104. # Create
  105. $InvoiceDataBackup = new InvoiceDataBackup();
  106. $InvoiceDataBackup->Invoice = $Invoice;
  107. $InvoiceDataBackup->data = $invoice;
  108. $InvoiceDataBackup->save();
  109. # Return InvoiceBackup
  110. return $InvoiceDataBackup;
  111. }
  112. public function getPath ( ) {
  113. # Prepare
  114. $invoices_path = Bal_App::getConfig('invoices_path') . DIRECTORY_SEPARATOR;
  115. # Handle
  116. $name = $this->id.'-'.md5(serialize($this->toArray(false))); // $this->id.'-'.$this->title;
  117. $invoice_path = $invoices_path . $name . '.pdf';
  118. # Return
  119. return $invoice_path;
  120. }
  121. public function download ( ) {
  122. # Prepare
  123. $invoice_path = $this->getPath();
  124. # Download
  125. become_file_download($invoice_path);
  126. # Done
  127. die;
  128. }
  129. public static function getTemplatePath ( $template ) {
  130. # Prepare
  131. $templates_path = Bal_App::getConfig('templates_path') . DIRECTORY_SEPARATOR;
  132. # Handle
  133. $template_path = $templates_path . 'invoice-'.$template.'.pdf';
  134. # Return path
  135. return $template_path;
  136. }
  137. public function generateFile ( ) {
  138. # Prepare
  139. $Locale = Bal_App::getLocale();
  140. $Invoice = $this;
  141. $InvoiceArray = $this->toArray(true);
  142. $Invoice_path = $this->getPath();
  143. $template_path = self::getTemplatePath($this->template);
  144. # Setup PDF + Meta
  145. $Pdf = Zend_Pdf::load($template_path);
  146. $Pdf->properties['Author'] = $Locale->translate('invoice-author');
  147. $Pdf->properties['Title'] = $Locale->translate('invoice-title', $Invoice);
  148. $Page = $Pdf->pages[0];
  149. # Font
  150. $font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_COURIER);
  151. $Page->setFont($font, 9);
  152. # Handle Matrix
  153. $template = $this->template;
  154. $function = '_matrix'.magic_function($template);
  155. if ( method_exists($this, $function) ) {
  156. $matrix = $this->$function();
  157. }
  158. # Translate Matrix
  159. foreach ( $matrix as $column => $details ) {
  160. # Fetch value
  161. $key = $column;
  162. $column = strtolower(str_replace('.','-',$key));
  163. $name = delve($details,'name',$column);
  164. $value = array_key_exists('value',$details) ? $details['value'] : delve($Invoice,$key,'');
  165. # Fetch type
  166. $type = delve($details,'type');
  167. if ( !$type ) {
  168. # Get field
  169. $field = delve($details,'field',$column);
  170. $Table = empty($details['table']) ? $this->getTable() : Doctrine::getTable($details['table']);
  171. $definition = $Table->getColumnDefinition($field);
  172. $type = delve($definition,'type');
  173. # Adjust
  174. if ( $type === 'enum' ) {
  175. $type = gettype($value);
  176. }
  177. elseif ( delve($definition,'extra.currency') ) {
  178. $type = 'currency';
  179. }
  180. }
  181. # Translate type
  182. if ( empty($type) ) $type = 'translate';
  183. $value = $Locale->translate_default('invoice-'.$name, array(
  184. 'value' => $Locale->$type($value),
  185. 'Invoice' => $InvoiceArray
  186. ),$Locale->$type($value));
  187. # Check translation
  188. $length = delve($details,'length');
  189. if ( $length && strlen($value) > $length ) {
  190. # Trim
  191. $value = substr($value,0,$length-4).' ...';
  192. }
  193. # Draw onto the PDF
  194. $Page->drawText($value, $details['position'][0], $details['position'][1]);
  195. }
  196. # Save PDF
  197. $Pdf->save($Invoice_path);
  198. # Prepare File
  199. $File = new File();
  200. $File->file = $Invoice_path;
  201. $File->url = Bal_App::getConfig('invoices_url') . DIRECTORY_SEPARATOR . $File->name;
  202. # Reset File
  203. Doctrine_Query::create()
  204. ->delete('File m')
  205. ->where('m.name = ?', $File->name)
  206. ->execute();
  207. # Save File
  208. $File->save();
  209. $this->File = $File;
  210. # Chain
  211. return $this;
  212. }
  213. protected function _matrixUserInvoice ( $Invoice ) {
  214. # Prepare
  215. $InvoiceItems = delve($Invoice,'InvoiceItems');
  216. # Set Matrix
  217. $matrix = array(
  218. # Invoice
  219. 'id' => array(
  220. 'position' => array(140,713),
  221. 'length' => 65
  222. ),
  223. 'price_total' => array(
  224. 'position' => array(190,436),
  225. 'length' => 70
  226. ),
  227. # Times
  228. 'created' => array(
  229. 'position' => array(405,713),
  230. 'length' => 65
  231. ),
  232. 'updated' => array(
  233. 'position' => array(220,748),
  234. 'length' => 65
  235. )
  236. );
  237. # Alter Matrix Depending on Code
  238. switch ( $code ) {
  239. case 'user_invoice':
  240. # Add Invoice Items
  241. $line_height = 15;
  242. foreach ( $InvoiceItems as $i => $InvoiceItem ) {
  243. # Title
  244. $matrix['invoiceitem-'.$InvoiceItem->id] = array(
  245. 'position' => array(150,519+$line_height*$i),
  246. 'length' => 55,
  247. 'value' => $InvoiceItem->title,
  248. 'type' => 'string'
  249. );
  250. # Cost
  251. $matrix['invoiceitem-'.$InvoiceItem->id] = array(
  252. 'position' => array(300,519+$line_height*$i),
  253. 'length' => 55,
  254. 'value' => $InvoiceItem->cost,
  255. 'type' => 'currency'
  256. );
  257. }
  258. # Done
  259. break;
  260. default:
  261. # Unkown
  262. throw new Zend_Exception('error-invoice-unknown_code');
  263. }
  264. # Return
  265. return $matrix;
  266. }
  267. /**
  268. * Ensure Messages
  269. * @param Doctrine_Event $Event
  270. * @return boolean success
  271. * @todo on postDelete remove messages that haven't been sent
  272. */
  273. public function ensureMessages($Event, $Event_type){
  274. # Check
  275. if ( !in_array($Event_type,array('postInsert')) ) {
  276. # Not designed for these events
  277. return null;
  278. }
  279. # Prepare
  280. $save = false;
  281. # Fetch
  282. $Invoice = $Event->getInvoker();
  283. # --------------------------
  284. # Messages
  285. # Create Invoice Insert Messages
  286. $Receivers = array(
  287. delve($Invoice,'UserFor'),
  288. delve($Invoice,'UserBy')
  289. );
  290. foreach ( $Receivers as $Receiver ) {
  291. $Message = new Message();
  292. $Message->UserFor = $Receiver;
  293. $Message->useTemplate('invoice-insert');
  294. $Message->save();
  295. }
  296. # --------------------------
  297. # Return save
  298. return $save;
  299. }
  300. /**
  301. * Ensure Totals
  302. * @param Doctrine_Event $Event
  303. * @return boolean success
  304. */
  305. public function ensureTotals($Event, $Event_type){
  306. # Check
  307. if ( !in_array($Event_type,array('preSave')) ) {
  308. # Not designed for these events
  309. return null;
  310. }
  311. # Fetch
  312. $Invoice = $Event->getInvoker();
  313. # --------------------------
  314. # Ensure
  315. # Apply Totals
  316. $Invoice->applyTotals();
  317. # --------------------------
  318. # Return true
  319. return true;
  320. }
  321. /**
  322. * Ensure Backup
  323. * @param Doctrine_Event $Event
  324. * @return boolean success
  325. */
  326. public function ensureBackup($Event, $Event_type){
  327. # Check
  328. if ( !in_array($Event_type,array('postSave')) ) {
  329. # Not designed for these events
  330. return null;
  331. }
  332. # Fetch
  333. $Invoice = $Event->getInvoker();
  334. # --------------------------
  335. # Ensure
  336. # Apply Totals
  337. $Invoice->backup();
  338. # --------------------------
  339. # Return false
  340. return false; // never save again
  341. }
  342. /**
  343. * Ensure Code
  344. * @param Doctrine_Event $Event
  345. * @return boolean success
  346. */
  347. public function ensureCode($Event, $Event_type){
  348. # Check
  349. if ( !in_array($Event_type,array('preInsert')) ) {
  350. # Not designed for these events
  351. return null;
  352. }
  353. # Prepare
  354. $save = false;
  355. # Fetch
  356. $Invoice = $Event->getInvoker();
  357. # --------------------------
  358. # Ensure
  359. # Check if code is set
  360. if ( !$Invoice->code ) {
  361. $Invoice->code = 'invoice-'.time();
  362. }
  363. # --------------------------
  364. # Return save
  365. return $save;
  366. }
  367. /**
  368. * Ensure Consistency
  369. * @param Doctrine_Event $Event
  370. * @return boolean wheter or not to save
  371. */
  372. public function ensure ( $Event, $Event_type ){
  373. return Bal_Doctrine_Core::ensure($Event,$Event_type,array(
  374. 'ensureCode',
  375. 'ensureTotals',
  376. 'ensureMessages',
  377. 'ensureBackup'
  378. ));
  379. }
  380. /**
  381. * preSave Event
  382. * @param Doctrine_Event $Event
  383. * @return
  384. */
  385. public function preSave ( $Event ) {
  386. # Prepare
  387. $result = true;
  388. # Ensure
  389. if ( self::ensure($Event, __FUNCTION__) ) {
  390. // no need
  391. }
  392. # Done
  393. return method_exists(get_parent_class($this),$parent_method = __FUNCTION__) ? parent::$parent_method($Event) : $result;
  394. }
  395. /**
  396. * postSave Event
  397. * @param Doctrine_Event $Event
  398. * @return
  399. */
  400. public function postSave ( $Event ) {
  401. # Prepare
  402. $Invoker = $Event->getInvoker();
  403. $result = true;
  404. # Ensure
  405. if ( self::ensure($Event, __FUNCTION__) ) {
  406. $Invoker->save();
  407. }
  408. # Done
  409. return method_exists(get_parent_class($this),$parent_method = __FUNCTION__) ? parent::$parent_method($Event) : $result;
  410. }
  411. /**
  412. * postInsert Event
  413. * @param Doctrine_Event $Event
  414. * @return
  415. */
  416. public function postInsert ( $Event ) {
  417. # Prepare
  418. $result = true;
  419. # Ensure
  420. if ( self::ensure($Event, __FUNCTION__) ) {
  421. // no need
  422. }
  423. # Done
  424. return method_exists(get_parent_class($this),$parent_method = __FUNCTION__) ? parent::$parent_method($Event) : $result;
  425. }
  426. /**
  427. * preInsert Event
  428. * @param Doctrine_Event $Event
  429. * @return
  430. */
  431. public function preInsert ( $Event ) {
  432. # Prepare
  433. $result = true;
  434. # Ensure
  435. if ( self::ensure($Event, __FUNCTION__) ) {
  436. // no need
  437. }
  438. # Done
  439. return method_exists(get_parent_class($this),$parent_method = __FUNCTION__) ? parent::$parent_method($Event) : $result;
  440. }
  441. # ========================
  442. # Payment Helpers
  443. /**
  444. * Process the Payment and Save changes
  445. * @param Bal_Payment_Model_Invoice
  446. * @return true
  447. */
  448. public function processPaymentAndSave ( Bal_Payment_Model_Invoice $PaymentInvoice ) {
  449. # Prepare
  450. $Invoice = $this;
  451. # Apply Payment Data
  452. $Invoice->payment_status = $PaymentInvoice->payment_status;
  453. $Invoice->payment_fee = $PaymentInvoice->payment_fee;
  454. $Invoice->paid_at = doctrine_timestamp($PaymentInvoice->paid_at);
  455. # Propogate to Invoice
  456. switch ( $Invoice->payment_status ) {
  457. case 'completed':
  458. $Invoice->status = 'completed';
  459. break;
  460. default:
  461. break;
  462. }
  463. # Save Invoice
  464. $Invoice->save();
  465. # Return true
  466. return true;
  467. }
  468. /**
  469. * Convert us into the Payment Model Representation
  470. * @return Bal_Payment_Model_Invoice
  471. */
  472. public function generatePaymentModel ( ) {
  473. # Prepare
  474. $Invoice = $this;
  475. $invoice = $Invoice->toArray(false);
  476. # Prepare PaymentInvoice
  477. $PaymentInvoice = new Bal_Payment_Model_Invoice();
  478. # Adjust Keys
  479. $keys = $PaymentInvoice->getKeys(); array_keys_keep($invoice, $keys);
  480. $invoice['id'] = $Invoice->code;
  481. # Apply the Payer
  482. $invoice['Payer'] = $Invoice->UserFor->generatePaymentModel();
  483. # Apply the InvoiceItems
  484. $invoice['InvoiceItems'] = array();
  485. foreach ( $Invoice->InvoiceItems as $InvoiceItem ) {
  486. $invoice['InvoiceItems'][] = $InvoiceItem->generatePaymentModel();
  487. }
  488. # Apply the Invoice
  489. $PaymentInvoice->merge($invoice);
  490. # Apply the Totals
  491. $PaymentInvoice->applyTotals();
  492. # Validate
  493. $PaymentInvoice->validate();
  494. # Return the PaymentInvoice
  495. return $PaymentInvoice;
  496. }
  497. /**
  498. * Calculate totals for ourself
  499. * @return true
  500. */
  501. public function applyTotals ( ) {
  502. # Prepare
  503. $Invoice = $this;
  504. # Apply Totals
  505. Bal_Payment_Model_Invoice::applyTotalsModel($Invoice);
  506. # Return true
  507. return true;
  508. }
  509. # ========================
  510. # CRUD Helpers
  511. /**
  512. * Fetch all the records for public access
  513. * @version 1.0, April 12, 2010
  514. * @return mixed
  515. */
  516. public static function fetch ( array $params = array() ) {
  517. # Prepare
  518. Bal_Doctrine_Core::prepareFetchParams($params,array('Invoice','User','UserFor','UserFrom'));
  519. extract($params);
  520. # Query
  521. $Query = Doctrine_Query::create()
  522. ->select('Invoice.*, InvoiceItem.*, Media.*')
  523. ->from('Invoice, Invoice.InvoiceItems InvoiceItem')
  524. ->orderBy('Invoice.created_at ASC');
  525. # Criteria
  526. if ( $User ) {
  527. $identifier = Bal_Doctrine_Core::resolveIdentifier('User',$User);
  528. $Query->andWhere(
  529. 'Invoice.UserFor.'.$identifier['column'].' = ? OR '.
  530. 'Invoice.UserFrom.'.$identifier['column'].' = ?',
  531. array($identifier['value'],$identifier['value'])
  532. );
  533. }
  534. if ( $UserFor ) {
  535. $identifier = Bal_Doctrine_Core::resolveIdentifier('User',$UserFor);
  536. $Query->andWhere(
  537. 'Invoice.UserFor.'.$identifier['column'].' = ?',
  538. $identifier['value']
  539. );
  540. }
  541. if ( $UserFrom ) {
  542. $identifier = Bal_Doctrine_Core::resolveIdentifier('User',$UserFrom);
  543. $Query->andWhere(
  544. 'Invoice.UserFrom.'.$identifier['column'].' = ?',
  545. $identifier['value']
  546. );
  547. }
  548. if ( $Invoice ) {
  549. $identifier = Bal_Doctrine_Core::resolveIdentifier('Invoice',$Invoice);
  550. $Query->andWhere(
  551. 'Invoice.'.$identifier['column'].' = ?',
  552. $identifier['value']
  553. );
  554. }
  555. # Fetch
  556. $result = Bal_Doctrine_Core::prepareFetchResult($params,$Query,'Invoice');
  557. # Done
  558. return $result;
  559. }
  560. }