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 ***********************************************************************/
13 Class for supplier/customer payment/credit allocations edition
16 //-----------------------------------------------------------------------------------
24 var $person_name = '';
25 var $person_type; // PT_SUPPLIER/PT_CUSTOMER
28 var $amount = 0; /*Total amount of the transaction in FX */
31 var $allocs; /*array of transactions allocated to */
33 function allocation($type, $trans_no, $person_id = null, $person_type_id=null)
35 $this->allocs = array();
37 $this->trans_no = $trans_no;
40 $this->set_person($person_id, $person_type_id);
42 $this->read($type, $trans_no, $person_id, $person_type_id); // read payment or credit
45 function set_person($person_id, $person_type)
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;
54 function add_item($type, $type_no, $date_, $due_date, $amount, $amount_allocated,
55 $current_allocated, $ref)
57 if (floatcmp($amount, 0))
59 $this->allocs[count($this->allocs)] = new allocation_item($type, $type_no,
60 $date_, $due_date, $amount, $amount_allocated, $current_allocated, $ref);
69 function update_item($index, $type, $type_no, $date_, $due_date,
70 $amount, $amount_allocated, $current_allocated, $ref)
72 if (floatcmp($amount, 0))
74 $this->allocs[$index] = new allocation_item($type, $type_no,
75 $date_, $due_date, $amount, $amount_allocated, $current_allocated, $ref);
84 function add_or_update_item($type, $type_no, $date_, $due_date,
85 $amount, $amount_allocated, $current_allocated, $ref)
87 for ($i = 0; $i < count($this->allocs); $i++)
89 $item = $this->allocs[$i];
90 if (($item->type == $type) && ($item->type_no == $type_no))
92 return $this->update_item($i, $type, $type_no, $date_, $due_date,
93 $amount, $amount_allocated, $current_allocated, $ref);
96 return $this->add_item($type, $type_no, $date_, $due_date,
97 $amount, $amount_allocated, $current_allocated, $ref);
101 // Read payment or credit current/available allocations to cart.
103 // FIXME - read all transactions below twice seems to be suboptimal
105 function read($type = null, $trans_no = 0, $person_id=null, $person_type_id=null)
107 if ($type !== null) { // otherwise re-read
109 $trans_no = $this->trans_no;
111 if (isset($person_type_id))
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)))
118 $bank_trans = db_fetch(get_bank_trans($type, $trans_no));
119 $this->person_type = $bank_trans['person_type_id'];
121 $this->person_type = in_array($type, array(ST_SUPPCREDIT, ST_SUPPAYMENT)) ? PT_SUPPLIER : PT_CUSTOMER;
125 $trans = $this->person_type == PT_SUPPLIER ? get_supp_trans($trans_no, $type, $person_id)
126 : get_customer_trans($trans_no, $type, $person_id);
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 = isset($trans["bank_amount"]) ? $trans["bank_amount"] : $trans["Total"]; // not set for journal entry
134 $this->amount = $trans["Total"];
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 */
141 $this->allocs = array();
142 if ($this->person_id)
144 if ($this->person_type==PT_SUPPLIER)
145 $trans_items = get_allocatable_to_supp_transactions($this->person_id);
147 $trans_items = get_allocatable_to_cust_transactions($this->person_id);
148 while ($myrow = db_fetch($trans_items))
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
156 $myrow["reference"]); // this allocation
159 if ($this->trans_no == 0) return; // this is new payment
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 */
165 if ($this->person_type==PT_SUPPLIER)
166 $trans_items = get_allocatable_to_supp_transactions($this->person_id,
167 $this->trans_no, $this->type);
169 $trans_items = get_allocatable_to_cust_transactions($this->person_id,
170 $this->trans_no, $this->type);
172 while ($myrow = db_fetch($trans_items))
174 $this->add_or_update_item ($myrow["type"], $myrow["trans_no"],
175 sql2date($myrow["tran_date"]),
176 sql2date($myrow["due_date"]),
178 $myrow["alloc"] - $myrow["amt"], $myrow["amt"], $myrow["reference"]);
182 // Update allocations in database.
186 global $no_exchange_variations;
190 if ($this->person_type == PT_SUPPLIER)
191 clear_supp_alloctions($this->type, $this->trans_no, $this->person_id, $this->date_);
193 clear_cust_alloctions($this->type, $this->trans_no, $this->person_id, $this->date_);
195 // now add the new allocations
196 $total_allocated = 0;
197 $dec = user_price_dec();
198 foreach ($this->allocs as $alloc_item)
200 if ($alloc_item->current_allocated > 0)
202 $amount = round($alloc_item->current_allocated, $dec);
204 if ($this->person_type == PT_SUPPLIER) {
205 add_supp_allocation($amount,
206 $this->type, $this->trans_no,
207 $alloc_item->type, $alloc_item->type_no, $this->person_id, $this->date_);
209 update_supp_trans_allocation($alloc_item->type, $alloc_item->type_no, $this->person_id);
211 add_cust_allocation($amount,
212 $this->type, $this->trans_no,
213 $alloc_item->type, $alloc_item->type_no, $this->person_id, $this->date_);
215 update_debtor_trans_allocation($alloc_item->type, $alloc_item->type_no, $this->person_id);
217 // Exchange Variations Joe Hunt 2008-09-20 ////////////////////
218 if ($alloc_item->type != ST_SALESORDER && !@$no_exchange_variations
219 && $alloc_item->type != ST_PURCHORDER && $alloc_item->type != ST_JOURNAL && $this->type != ST_JOURNAL)
220 exchange_variation($this->type, $this->trans_no,
221 $alloc_item->type, $alloc_item->type_no, $this->date_,
222 $amount, $this->person_type);
224 //////////////////////////////////////////////////////////////
225 $total_allocated += $alloc_item->current_allocated;
228 } /*end of the loop through the array of allocations made */
229 if ($this->person_type == PT_SUPPLIER)
230 update_supp_trans_allocation($this->type, $this->trans_no, $this->person_id);
232 update_debtor_trans_allocation($this->type, $this->trans_no, $this->person_id);
234 commit_transaction();
240 //-----------------------------------------------------------------------------------
242 class allocation_item
251 var $amount_allocated;
255 var $current_allocated;
257 function allocation_item ($type, $type_no, $date_, $due_date, $amount,
258 $amount_allocated, $current_allocated, $ref)
262 $this->type_no = $type_no;
266 $this->date_ = $date_;
267 $this->due_date = $due_date;
269 $this->amount = $amount;
270 $this->amount_allocated = $amount_allocated;
271 $this->current_allocated = $current_allocated;
275 //--------------------------------------------------------------------------------
277 function show_allocatable($show_totals) {
279 global $systypes_array;
281 $k = $counter = $total_allocated = 0;
283 $cart = $_SESSION['alloc'];
284 $supp_ref = in_array($cart->type, array(ST_SUPPCREDIT, ST_SUPPAYMENT, ST_BANKPAYMENT));
286 if (count($cart->allocs))
288 // if ($cart->currency != $cart->person_curr)
289 display_heading(sprintf(_("Allocated amounts in %s:"), $cart->person_curr));
290 start_table(TABLESTYLE, "width='60%'");
291 $th = array(_("Transaction Type"), _("#"), $supp_ref ? _("Supplier Ref"): _("Ref"), _("Date"), _("Due Date"), _("Amount"),
292 _("Other Allocations"), _("Left to Allocate"), _("This Allocation"),'','');
296 foreach ($cart->allocs as $id => $alloc_item)
298 if (floatcmp(abs($alloc_item->amount), $alloc_item->amount_allocated))
300 alt_table_row_color($k);
301 label_cell($systypes_array[$alloc_item->type]);
302 label_cell(get_trans_view_str($alloc_item->type, $alloc_item->type_no));
303 label_cell($alloc_item->ref);
304 label_cell($alloc_item->date_, "align=right");
305 label_cell($alloc_item->due_date, "align=right");
306 amount_cell(abs($alloc_item->amount));
307 amount_cell($alloc_item->amount_allocated);
309 $_POST['amount' . $id] = price_format($alloc_item->current_allocated);
311 $un_allocated = round((abs($alloc_item->amount) - $alloc_item->amount_allocated), 6);
312 amount_cell($un_allocated, false,'', 'maxval'.$id);
313 amount_cells(null, "amount" . $id);//, input_num('amount' . $id));
314 label_cell("<a href='#' name=Alloc$id onclick='allocate_all(this.name.substr(5));return true;'>"
315 . _("All") . "</a>");
316 label_cell("<a href='#' name=DeAll$id onclick='allocate_none(this.name.substr(5));return true;'>"
317 . _("None") . "</a>".hidden("un_allocated" . $id,
318 price_format($un_allocated), false));
321 $total_allocated += input_num('amount' . $id);
325 label_row(_("Total Allocated"), price_format($total_allocated),
326 "colspan=8 align=right", "align=right id='total_allocated'", 3);
328 $amount = $_SESSION['alloc']->amount;
330 if ($_SESSION['alloc']->type == ST_SUPPCREDIT
331 || $_SESSION['alloc']->type == ST_SUPPAYMENT
332 || $_SESSION['alloc']->type == ST_BANKPAYMENT ||
333 ($_SESSION['alloc']->type == ST_JOURNAL && $_SESSION['alloc']->person_type == PT_SUPPLIER))
336 $amount = abs($cart->amount);
338 if (floatcmp($amount, $total_allocated) < 0)
340 $font1 = "<font color=red>";
344 $font1 = $font2 = "";
345 $left_to_allocate = price_format($amount - $total_allocated);
346 label_row(_("Left to Allocate"), $font1 . $left_to_allocate . $font2,
347 "colspan=8 align=right", "nowrap align=right id='left_to_allocate'",
352 hidden('TotalNumberOfAllocs', count($cart->allocs));
354 //--------------------------------------------------------------------------------
356 function check_allocations()
360 $total_allocated = 0;
362 for ($counter = 0; $counter < get_post("TotalNumberOfAllocs"); $counter++)
364 if (!isset($_POST['amount'.$counter])) continue;
365 if (!check_num('amount' . $counter, 0))
367 display_error(_("The entry for one or more amounts is invalid or negative."));
368 set_focus('amount'.$counter);
372 /* Now check to see that the AllocAmt is no greater than the
373 amount left to be allocated against the transaction under review;
374 skip check if no allocation is set to avoid deadlock on mistakenly overallocated transactions*/
375 $allocated = input_num('amount' . $counter);
376 if ($allocated && ($allocated > input_num('un_allocated' . $counter)))
378 display_error(_("At least one transaction is overallocated."));
379 set_focus('amount'.$counter);
383 $_SESSION['alloc']->allocs[$counter]->current_allocated = input_num('amount' . $counter);
385 $total_allocated += input_num('amount' . $counter);
388 $amount = $_SESSION['alloc']->amount;
390 if (in_array($_SESSION['alloc']->type, array(ST_BANKPAYMENT, ST_SUPPCREDIT, ST_SUPPAYMENT)) ||
391 ($_SESSION['alloc']->type==ST_JOURNAL && $_SESSION['alloc']->person_type == PT_SUPPLIER))
394 $amount = abs($_SESSION['alloc']->amount);
396 if ($total_allocated - ($amount + input_num('discount')) > $SysPrefs->allocation_settled_allowance())
398 display_error(_("These allocations cannot be processed because the amount allocated is more than the total amount left to allocate."));
405 //----------------------------------------------------------------------------------------
407 // Returns sales or purchase invoice allocations to be reallocated after invoice edition.
409 function get_inv_allocations($trans_no, $trans_type, $person_id)
412 if ($trans_type == ST_SUPPINVOICE || $trans_type == ST_SUPPCREDIT)
413 $result = get_allocatable_from_supp_transactions($person_id, $trans_no, $trans_type);
415 $result = get_allocatable_from_cust_transactions($person_id, $trans_no, $trans_type);
417 while($dat = db_fetch($result))
419 $allocs[] = array('type'=> $dat['type'], 'trans_no'=> $dat['trans_no'], 'amount'=>$dat['alloc']);