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