2821fe5fe7874786443bb72f0a65ea0e50c669c7
[fa-stable.git] / includes / ui / allocation_cart.inc
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 /*
13         Class for supplier/customer payment/credit allocations edition
14         and related helpers.
15 */
16 //-----------------------------------------------------------------------------------
17
18 class allocation 
19 {
20
21         var $trans_no; 
22         var $type;
23         var $person_id = '';
24         var $person_name = '';
25         var $person_type;       // PT_SUPPLIER/PT_CUSTOMER
26         var $person_curr;
27         var $date_;
28         var $amount = 0; /*Total amount of the transaction in FX */
29         var $currency;
30
31         var $allocs; /*array of transactions allocated to */
32
33         function allocation($type, $trans_no, $person_id = null, $person_type_id=null)
34         {
35                 $this->allocs = array();
36
37                 $this->trans_no = $trans_no;
38                 $this->type = $type;
39                 if ($person_id)
40                         $this->set_person($person_id, $person_type_id);
41
42                 $this->read($type, $trans_no, $person_id, $person_type_id); // read payment or credit
43         }
44
45         function set_person($person_id, $person_type)
46         {
47                 $this->person_id = $person_id;
48                 $this->person_type = $person_type;
49                 $this->person_curr = $person_type == PT_SUPPLIER ?
50                         get_supplier_currency($person_id) : get_customer_currency($person_id);
51                 return $this->person_curr;
52         }
53
54         function add_item($type, $type_no, $date_, $due_date, $amount, $amount_allocated, 
55                 $current_allocated, $ref)
56         {
57                 if (floatcmp($amount, 0))
58                 {
59                         $this->allocs[count($this->allocs)] = new allocation_item($type, $type_no, 
60                                 $date_, $due_date, $amount, $amount_allocated, $current_allocated, $ref);
61                         return true;
62                 } 
63                 else 
64                 {
65                         return false;
66                 }
67         }
68         
69         function update_item($index, $type, $type_no, $date_, $due_date, 
70                 $amount, $amount_allocated, $current_allocated, $ref)
71         {
72                 if (floatcmp($amount, 0))
73                 {
74                         $this->allocs[$index] = new allocation_item($type, $type_no, 
75                                 $date_, $due_date, $amount, $amount_allocated, $current_allocated, $ref);
76                         return true;
77                 } 
78                 else 
79                 {
80                         return false;
81                 }
82         }
83         
84         function add_or_update_item($type, $type_no, $date_, $due_date, 
85                 $amount, $amount_allocated, $current_allocated, $ref)
86         {
87                 for ($i = 0; $i < count($this->allocs); $i++) 
88                 {
89                         $item = $this->allocs[$i];
90                         if (($item->type == $type) && ($item->type_no == $type_no)) 
91                         {
92                                 return $this->update_item($i, $type, $type_no, $date_, $due_date, 
93                                         $amount, $amount_allocated, $current_allocated, $ref);
94                         }
95                 }
96         return $this->add_item($type, $type_no, $date_, $due_date, 
97                 $amount, $amount_allocated, $current_allocated, $ref);
98         }
99
100         //
101         //      Read payment or credit current/available allocations to cart.
102         //
103         // FIXME - read all transactions below twice seems to be suboptimal
104         //
105         function read($type = null, $trans_no = 0, $person_id=null, $person_type_id=null)
106         {
107                 if ($type !== null) {   // otherwise re-read
108                         $type = $this->type;
109                         $trans_no = $this->trans_no;
110
111                         if (isset($person_type_id))
112                         {
113                                 $this->person_type = $person_type_id;
114                                 $this->person_id = $person_id;
115                         } else { // guess person_type_id
116                                 if (in_array($type, array(ST_BANKPAYMENT, ST_BANKDEPOSIT)))
117                                 {
118                                         $bank_trans = db_fetch(get_bank_trans($type, $trans_no));
119                                         $this->person_type = $bank_trans['person_type_id'];
120                                 } else
121                                         $this->person_type = in_array($type, array(ST_SUPPCREDIT, ST_SUPPAYMENT)) ? PT_SUPPLIER : PT_CUSTOMER;
122                         }
123
124                         if ($trans_no) {
125                                 $trans = $this->person_type == PT_SUPPLIER ? get_supp_trans($trans_no, $type, $person_id)
126                                         : get_customer_trans($trans_no, $type, $person_id);
127
128                                 $this->person_id = $trans[$this->person_type == PT_SUPPLIER ? 'supplier_id':'debtor_no'];
129                                 $this->person_name = $trans[$this->person_type == PT_SUPPLIER ? "supplier_name":"DebtorName"];
130                                 $this->date_ = sql2date($trans["tran_date"]);
131                                 $this->person_curr = $trans['curr_code'];
132                                 $this->currency = isset($trans['bank_curr_code']) ? $trans['bank_curr_code'] : $trans['curr_code'];
133                                 $this->bank_amount = @$trans["bank_amount"];
134                                 $this->amount = $trans["Total"];
135                         } else
136                                 $this->date_ = Today();
137                 }
138         /* Now populate the array of possible (and previous actual) allocations 
139                 for this customer/supplier. First get the transactions that have 
140                 outstanding balances ie Total-alloc >0 */
141
142                 $this->allocs = array();
143                 if ($this->person_id)
144                 {
145                         if ($this->person_type==PT_SUPPLIER)
146                                 $trans_items = get_allocatable_to_supp_transactions($this->person_id);
147                         else
148                                 $trans_items = get_allocatable_to_cust_transactions($this->person_id);
149                         while ($myrow = db_fetch($trans_items))
150                         {
151                                 $this->add_item($myrow["type"], $myrow["trans_no"],
152                                         sql2date($myrow["tran_date"]),
153                                         sql2date($myrow["due_date"]),
154                                         $myrow["Total"], // trans total
155                                         $myrow["alloc"], // trans total allocated
156                                         0,
157                                         $myrow["reference"]); // this allocation
158                         }
159                 }
160                 if ($this->trans_no == 0) return; // this is new payment
161
162         /* Now get trans that might have previously been allocated to by this trans
163         NB existing entries where still some of the trans outstanding entered from
164         above logic will be overwritten with the prev alloc detail below */
165
166                 if ($this->person_type==PT_SUPPLIER)
167                         $trans_items = get_allocatable_to_supp_transactions($this->person_id, 
168                                 $this->trans_no, $this->type);
169                 else
170                         $trans_items = get_allocatable_to_cust_transactions($this->person_id, 
171                                 $this->trans_no, $this->type);
172
173                 while ($myrow = db_fetch($trans_items))
174                 {
175                         $this->add_or_update_item ($myrow["type"], $myrow["trans_no"],
176                                 sql2date($myrow["tran_date"]),
177                                 sql2date($myrow["due_date"]),
178                                 $myrow["Total"],
179                                 $myrow["alloc"] - $myrow["amt"], $myrow["amt"], $myrow["reference"]);
180                 }
181         }
182         //
183         //      Update allocations in database.
184         //
185         function write()
186         {
187                 begin_transaction();
188
189                 if ($this->person_type == PT_SUPPLIER)
190                         clear_supp_alloctions($this->type, $this->trans_no, $this->date_);
191                 else
192                         clear_cust_alloctions($this->type, $this->trans_no, $this->date_);
193
194                 // now add the new allocations
195                 $total_allocated = 0;
196                 $dec = user_price_dec();
197                 foreach ($this->allocs as $alloc_item)
198                 {
199                         if ($alloc_item->current_allocated > 0)
200                         {
201                                 $amount = round($alloc_item->current_allocated, $dec);
202
203                                 if ($this->person_type == PT_SUPPLIER) {
204                                         add_supp_allocation($amount,
205                                                 $this->type, $this->trans_no,
206                                         $alloc_item->type, $alloc_item->type_no, $this->date_);
207
208                                         update_supp_trans_allocation($alloc_item->type, $alloc_item->type_no);
209                                 } else {
210                                         add_cust_allocation($amount,
211                                                 $this->type, $this->trans_no,
212                                         $alloc_item->type, $alloc_item->type_no, $this->date_);
213
214                                         update_debtor_trans_allocation($alloc_item->type, $alloc_item->type_no);
215                                 }
216                                 // Exchange Variations Joe Hunt 2008-09-20 ////////////////////
217                                 exchange_variation($this->type, $this->trans_no,
218                                         $alloc_item->type, $alloc_item->type_no, $this->date_,
219                                         $amount, $this->person_type);
220
221                                 //////////////////////////////////////////////////////////////
222                                 $total_allocated += $alloc_item->current_allocated;
223                         }
224
225                 }  /*end of the loop through the array of allocations made */
226                 if ($this->person_type == PT_SUPPLIER)
227                         update_supp_trans_allocation($this->type, $this->trans_no);
228                 else
229                         update_debtor_trans_allocation($this->type,     $this->trans_no);
230
231                 commit_transaction();
232
233         }
234
235
236
237 //-----------------------------------------------------------------------------------
238
239 class allocation_item 
240 {
241
242         var $type;
243         var $type_no;
244         
245         var $date_;
246         var $due_date;
247         
248         var $amount_allocated;
249         var $amount;
250         var $ref;
251         
252         var $current_allocated;
253         
254         function allocation_item ($type, $type_no, $date_, $due_date, $amount, 
255                 $amount_allocated, $current_allocated, $ref)
256         {
257
258                 $this->type = $type;
259                 $this->type_no = $type_no;
260
261                 $this->ref = $ref;
262
263                 $this->date_ = $date_;
264                 $this->due_date = $due_date;
265                 
266                 $this->amount = $amount;
267                 $this->amount_allocated = $amount_allocated;
268                 $this->current_allocated = $current_allocated;
269         }
270 }
271
272 //--------------------------------------------------------------------------------
273
274 function show_allocatable($show_totals) {
275
276         global $systypes_array;
277         
278     $k = $counter = $total_allocated = 0;
279
280         $cart = $_SESSION['alloc'];
281         $supp_ref = in_array($cart->type, array(ST_SUPPCREDIT, ST_SUPPAYMENT, ST_BANKPAYMENT));
282
283         if (count($cart->allocs)) 
284         {
285                 if ($cart->currency != $cart->person_curr)
286                         display_heading(sprintf(_("Allocated amounts in %s:"), $cart->person_curr));
287                 start_table(TABLESTYLE, "width=60%");
288                 $th = array(_("Transaction Type"), _("#"), $supp_ref ? _("Supplier Ref"): _("Ref"), _("Date"), _("Due Date"), _("Amount"),
289                         _("Other Allocations"), _("Left to Allocate"), _("This Allocation"),'','');
290
291                 table_header($th);
292
293                 foreach ($cart->allocs as $id => $alloc_item)
294                 {
295                     if (floatcmp(abs($alloc_item->amount), $alloc_item->amount_allocated))
296                     {
297                                 alt_table_row_color($k);
298                         label_cell($systypes_array[$alloc_item->type]);
299                                 label_cell(get_trans_view_str($alloc_item->type, $alloc_item->type_no));
300                                 label_cell($alloc_item->ref);
301                         label_cell($alloc_item->date_, "align=right");
302                         label_cell($alloc_item->due_date, "align=right");
303                         amount_cell(abs($alloc_item->amount));
304                                 amount_cell($alloc_item->amount_allocated);
305
306                         $_POST['amount' . $id] = price_format($alloc_item->current_allocated);
307
308                         $un_allocated = round((abs($alloc_item->amount) - $alloc_item->amount_allocated), 6);
309                         amount_cell($un_allocated, false,'', 'maxval'.$id);
310                         amount_cells(null, "amount" . $id);//, input_num('amount' . $id));
311                                 label_cell("<a href='#' name=Alloc$id onclick='allocate_all(this.name.substr(5));return true;'>"
312                                          . _("All") . "</a>");
313                                 label_cell("<a href='#' name=DeAll$id onclick='allocate_none(this.name.substr(5));return true;'>"
314                                          . _("None") . "</a>".hidden("un_allocated" . $id, 
315                                          price_format($un_allocated), false));
316                                 end_row();
317
318                         $total_allocated += input_num('amount' . $id);
319                         }
320                 }
321                 if ($show_totals) {
322                 label_row(_("Total Allocated"), price_format($total_allocated),
323                         "colspan=8 align=right", "align=right id='total_allocated'", 3);
324 /*
325                         $amount = $_SESSION['alloc']->amount;
326
327                         if ($_SESSION['alloc']->type == ST_SUPPCREDIT
328                                 || $_SESSION['alloc']->type == ST_SUPPAYMENT
329                                 ||  $_SESSION['alloc']->type == ST_BANKPAYMENT)
330                                 $amount = -$amount;
331 */
332                         $amount = abs($cart->amount);
333
334                         if (floatcmp($amount, $total_allocated) < 0)
335                 {
336                         $font1 = "<font color=red>";
337                         $font2 = "</font>";
338             }
339                 else
340                         $font1 = $font2 = "";
341                         $left_to_allocate = price_format($amount - $total_allocated);
342                 label_row(_("Left to Allocate"), $font1 . $left_to_allocate . $font2, 
343                                 "colspan=8 align=right", "nowrap align=right id='left_to_allocate'",
344                                  3);
345                 }
346                 end_table(1);
347         }
348         hidden('TotalNumberOfAllocs', count($cart->allocs));
349 }
350 //--------------------------------------------------------------------------------
351
352 function check_allocations()
353 {
354         global $SysPrefs;
355
356         $total_allocated = 0;
357
358         for ($counter = 0; $counter < get_post("TotalNumberOfAllocs"); $counter++)
359         {
360                 if (!isset($_POST['amount'.$counter])) continue;
361                 if (!check_num('amount' . $counter, 0))
362                 {
363                         display_error(_("The entry for one or more amounts is invalid or negative."));
364                         set_focus('amount'.$counter);
365                         return false;
366                  }
367
368                   /* Now check to see that the AllocAmt is no greater than the
369                  amount left to be allocated against the transaction under review;
370                  skip check if no allocation is set to avoid deadlock on mistakenly overallocated transactions*/
371                  $allocated = input_num('amount' . $counter);
372                  if ($allocated && ($allocated > input_num('un_allocated' . $counter)))
373                  {
374                         display_error(_("At least one transaction is overallocated."));
375                         set_focus('amount'.$counter);
376                         return false;
377                  }
378
379                  $_SESSION['alloc']->allocs[$counter]->current_allocated = input_num('amount' . $counter);
380
381                  $total_allocated += input_num('amount' . $counter);
382         }
383 /*
384         $amount = $_SESSION['alloc']->amount;
385
386         if (in_array($_SESSION['alloc']->type, array(ST_BANKPAYMENT, ST_SUPPCREDIT, ST_SUPPAYMENT)))
387                 $amount = -$amount;
388 */
389         $amount = abs($_SESSION['alloc']->amount);
390
391         if ($total_allocated - ($amount + input_num('discount'))  > $SysPrefs->allocation_settled_allowance())
392         {
393                 display_error(_("These allocations cannot be processed because the amount allocated is more than the total amount left to allocate."));
394                 return false;
395         }
396
397         return true;
398 }