Bank Payment View, Bank Deposit View: fixed 'left to allocate' amount, added value...
[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                         }
136                 }
137         /* Now populate the array of possible (and previous actual) allocations 
138                 for this customer/supplier. First get the transactions that have 
139                 outstanding balances ie Total-alloc >0 */
140
141                 $this->allocs = array();
142                 if ($this->person_id)
143                 {
144                         if ($this->person_type==PT_SUPPLIER)
145                                 $trans_items = get_allocatable_to_supp_transactions($this->person_id);
146                         else
147                                 $trans_items = get_allocatable_to_cust_transactions($this->person_id);
148                         while ($myrow = db_fetch($trans_items))
149                         {
150                                 $this->add_item($myrow["type"], $myrow["trans_no"],
151                                         sql2date($myrow["tran_date"]),
152                                         sql2date($myrow["due_date"]),
153                                         $myrow["Total"], // trans total
154                                         $myrow["alloc"], // trans total allocated
155                                         0,
156                                         $myrow["reference"]); // this allocation
157                         }
158                 }
159                 if ($this->trans_no == 0) return; // this is new payment
160
161         /* Now get trans that might have previously been allocated to by this trans
162         NB existing entries where still some of the trans outstanding entered from
163         above logic will be overwritten with the prev alloc detail below */
164
165                 if ($this->person_type==PT_SUPPLIER)
166                         $trans_items = get_allocatable_to_supp_transactions($this->person_id, 
167                                 $this->trans_no, $this->type);
168                 else
169                         $trans_items = get_allocatable_to_cust_transactions($this->person_id, 
170                                 $this->trans_no, $this->type);
171
172                 while ($myrow = db_fetch($trans_items))
173                 {
174                         $this->add_or_update_item ($myrow["type"], $myrow["trans_no"],
175                                 sql2date($myrow["tran_date"]),
176                                 sql2date($myrow["due_date"]),
177                                 $myrow["Total"],
178                                 $myrow["alloc"] - $myrow["amt"], $myrow["amt"], $myrow["reference"]);
179                 }
180         }
181         //
182         //      Update allocations in database.
183         //
184         function write()
185         {
186                 begin_transaction();
187
188                 if ($this->person_type == PT_SUPPLIER)
189                         clear_supp_alloctions($this->type, $this->trans_no, $this->date_);
190                 else
191                         clear_cust_alloctions($this->type, $this->trans_no, $this->date_);
192
193                 // now add the new allocations
194                 $total_allocated = 0;
195                 $dec = user_price_dec();
196                 foreach ($this->allocs as $alloc_item)
197                 {
198                         if ($alloc_item->current_allocated > 0)
199                         {
200                                 $amount = round($alloc_item->current_allocated, $dec);
201
202                                 if ($this->person_type == PT_SUPPLIER) {
203                                         add_supp_allocation($amount,
204                                                 $this->type, $this->trans_no,
205                                         $alloc_item->type, $alloc_item->type_no, $this->date_);
206
207                                         update_supp_trans_allocation($alloc_item->type, $alloc_item->type_no);
208                                 } else {
209                                         add_cust_allocation($amount,
210                                                 $this->type, $this->trans_no,
211                                         $alloc_item->type, $alloc_item->type_no, $this->date_);
212
213                                         update_debtor_trans_allocation($alloc_item->type, $alloc_item->type_no);
214                                 }
215                                 // Exchange Variations Joe Hunt 2008-09-20 ////////////////////
216                                 exchange_variation($this->type, $this->trans_no,
217                                         $alloc_item->type, $alloc_item->type_no, $this->date_,
218                                         $amount, $this->person_type);
219
220                                 //////////////////////////////////////////////////////////////
221                                 $total_allocated += $alloc_item->current_allocated;
222                         }
223
224                 }  /*end of the loop through the array of allocations made */
225                 if ($this->person_type == PT_SUPPLIER)
226                         update_supp_trans_allocation($this->type, $this->trans_no);
227                 else
228                         update_debtor_trans_allocation($this->type,     $this->trans_no);
229
230                 commit_transaction();
231
232         }
233
234
235
236 //-----------------------------------------------------------------------------------
237
238 class allocation_item 
239 {
240
241         var $type;
242         var $type_no;
243         
244         var $date_;
245         var $due_date;
246         
247         var $amount_allocated;
248         var $amount;
249         var $ref;
250         
251         var $current_allocated;
252         
253         function allocation_item ($type, $type_no, $date_, $due_date, $amount, 
254                 $amount_allocated, $current_allocated, $ref)
255         {
256
257                 $this->type = $type;
258                 $this->type_no = $type_no;
259
260                 $this->ref = $ref;
261
262                 $this->date_ = $date_;
263                 $this->due_date = $due_date;
264                 
265                 $this->amount = $amount;
266                 $this->amount_allocated = $amount_allocated;
267                 $this->current_allocated = $current_allocated;
268         }
269 }
270
271 //--------------------------------------------------------------------------------
272
273 function show_allocatable($show_totals) {
274
275         global $systypes_array;
276         
277     $k = $counter = $total_allocated = 0;
278
279         $cart = $_SESSION['alloc'];
280         $supp_ref = in_array($cart->type, array(ST_SUPPCREDIT, ST_SUPPAYMENT, ST_BANKPAYMENT));
281
282         if (count($cart->allocs)) 
283         {
284                 if ($cart->currency != $cart->person_curr)
285                         display_heading(sprintf(_("Allocated amounts in %s:"), $cart->person_curr));
286                 start_table(TABLESTYLE, "width=60%");
287                 $th = array(_("Transaction Type"), _("#"), $supp_ref ? _("Supplier Ref"): _("Ref"), _("Date"), _("Due Date"), _("Amount"),
288                         _("Other Allocations"), _("Left to Allocate"), _("This Allocation"),'','');
289
290                 table_header($th);
291
292                 foreach ($cart->allocs as $id => $alloc_item)
293                 {
294                     if (floatcmp(abs($alloc_item->amount), $alloc_item->amount_allocated))
295                     {
296                                 alt_table_row_color($k);
297                         label_cell($systypes_array[$alloc_item->type]);
298                                 label_cell(get_trans_view_str($alloc_item->type, $alloc_item->type_no));
299                                 label_cell($alloc_item->ref);
300                         label_cell($alloc_item->date_, "align=right");
301                         label_cell($alloc_item->due_date, "align=right");
302                         amount_cell(abs($alloc_item->amount));
303                                 amount_cell($alloc_item->amount_allocated);
304
305                         $_POST['amount' . $id] = price_format($alloc_item->current_allocated);
306
307                         $un_allocated = round((abs($alloc_item->amount) - $alloc_item->amount_allocated), 6);
308                         amount_cell($un_allocated, false,'', 'maxval'.$id);
309                         amount_cells(null, "amount" . $id);//, input_num('amount' . $id));
310                                 label_cell("<a href='#' name=Alloc$id onclick='allocate_all(this.name.substr(5));return true;'>"
311                                          . _("All") . "</a>");
312                                 label_cell("<a href='#' name=DeAll$id onclick='allocate_none(this.name.substr(5));return true;'>"
313                                          . _("None") . "</a>".hidden("un_allocated" . $id, 
314                                          price_format($un_allocated), false));
315                                 end_row();
316
317                         $total_allocated += input_num('amount' . $id);
318                         }
319                 }
320                 if ($show_totals) {
321                 label_row(_("Total Allocated"), price_format($total_allocated),
322                         "colspan=8 align=right", "align=right id='total_allocated'", 3);
323 /*
324                         $amount = $_SESSION['alloc']->amount;
325
326                         if ($_SESSION['alloc']->type == ST_SUPPCREDIT
327                                 || $_SESSION['alloc']->type == ST_SUPPAYMENT
328                                 ||  $_SESSION['alloc']->type == ST_BANKPAYMENT)
329                                 $amount = -$amount;
330 */
331                         $amount = abs($cart->amount);
332
333                         if (floatcmp($amount, $total_allocated) < 0)
334                 {
335                         $font1 = "<font color=red>";
336                         $font2 = "</font>";
337             }
338                 else
339                         $font1 = $font2 = "";
340                         $left_to_allocate = price_format($amount - $total_allocated);
341                 label_row(_("Left to Allocate"), $font1 . $left_to_allocate . $font2, 
342                                 "colspan=8 align=right", "nowrap align=right id='left_to_allocate'",
343                                  3);
344                 }
345                 end_table(1);
346         }
347         hidden('TotalNumberOfAllocs', count($cart->allocs));
348 }
349 //--------------------------------------------------------------------------------
350
351 function check_allocations()
352 {
353         global $SysPrefs;
354
355         $total_allocated = 0;
356
357         for ($counter = 0; $counter < get_post("TotalNumberOfAllocs"); $counter++)
358         {
359                 if (!isset($_POST['amount'.$counter])) continue;
360                 if (!check_num('amount' . $counter, 0))
361                 {
362                         display_error(_("The entry for one or more amounts is invalid or negative."));
363                         set_focus('amount'.$counter);
364                         return false;
365                  }
366
367                   /* Now check to see that the AllocAmt is no greater than the
368                  amount left to be allocated against the transaction under review;
369                  skip check if no allocation is set to avoid deadlock on mistakenly overallocated transactions*/
370                  $allocated = input_num('amount' . $counter);
371                  if ($allocated && ($allocated > input_num('un_allocated' . $counter)))
372                  {
373                         display_error(_("At least one transaction is overallocated."));
374                         set_focus('amount'.$counter);
375                         return false;
376                  }
377
378                  $_SESSION['alloc']->allocs[$counter]->current_allocated = input_num('amount' . $counter);
379
380                  $total_allocated += input_num('amount' . $counter);
381         }
382 /*
383         $amount = $_SESSION['alloc']->amount;
384
385         if (in_array($_SESSION['alloc']->type, array(ST_BANKPAYMENT, ST_SUPPCREDIT, ST_SUPPAYMENT)))
386                 $amount = -$amount;
387 */
388         $amount = abs($_SESSION['alloc']->amount);
389
390         if ($total_allocated - ($amount + input_num('discount'))  > $SysPrefs->allocation_settled_allowance())
391         {
392                 display_error(_("These allocations cannot be processed because the amount allocated is more than the total amount left to allocate."));
393                 return false;
394         }
395
396         return true;
397 }