New tax system implementation.
[fa-stable.git] / purchasing / includes / po_class.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 /* Definition of the purch_order class to hold all the information for a purchase order and delivery
13 */
14
15 class purch_order 
16 {
17
18         var $trans_type; // order/grn/invoice (direct)
19         var $supplier_id;
20         var $Comments;
21         var $tran_date;
22         var $reference;
23         var $supp_ref;
24         var $Location;
25         var $delivery_address;
26
27         var $prep_amount = 0; // prepayment required
28         var $alloc; // sum of payments allocated
29         var $tax_included; // type of prices
30
31         var $line_items;
32         var $curr_code;
33         var $supplier_name;
34         var $due_date;
35         var $order_no; /*Only used for modification of existing orders otherwise only established when order committed */
36         var $lines_on_order = 0;
37         var $credit;
38         var $tax_group_id;
39         var $terms;
40         var $ex_rate;
41         var $cash_account;
42         var $dimension,
43                 $dimension2;
44
45         var $tax_overrides = array();           // array of taxes manually inserted during sales invoice entry (direct invoice)
46
47         var $prepayments = array();
48
49         var $fixed_asset = false;
50         var $grn_id ;   // grn batch id used in edition only
51
52         function __construct()
53         {
54                 $this->line_items = array();
55                 $this->lines_on_order = $this->order_no = $this->supplier_id = 0;
56                 $this->tax_group_id = find_domestic_tax_group(); // prevent tax errors until supplier is selected
57         }
58         
59         function set_supplier($supplier_id, $supplier_name, $curr_code, $tax_group_id, $tax_included, $tax_area)
60         {
61                 $this->supplier_id = $supplier_id;
62                 $this->supplier_name = $supplier_name;
63                 $this->curr_code = $curr_code;
64                 $this->tax_group_id = $tax_group_id;
65                 $this->tax_included = $tax_included;
66                 $this->tax_area = $tax_area;
67         }
68         
69         function add_to_order($line_no, $stock_id, $qty, $item_descr, $price, $uom, $req_del_date, $qty_inv, $qty_recd, $qty_ordered=0, $grn_item_id=0)
70         {
71                 if (isset($qty) && $qty != 0)
72                 {
73                         $this->line_items[$line_no] = new po_line_details($line_no, $stock_id, $item_descr, $qty, $price, $uom, 
74                                 $req_del_date, $qty_inv, $qty_recd, $qty_ordered, $grn_item_id);
75                         $this->lines_on_order++;
76                         return 1;
77                 }
78                 return 0;
79         }
80
81         function update_order_item($line_no, $qty, $price, $req_del_date, $description="")
82         {
83                 if ($description != "")
84                         $this->line_items[$line_no]->item_description = $description;
85                 $this->line_items[$line_no]->quantity = $qty;
86                 $this->line_items[$line_no]->price = $price;
87                 $this->line_items[$line_no]->req_del_date = $req_del_date;
88                 $this->line_items[$line_no]->item_description = $description;
89         }
90
91         function remove_from_order($line_no)
92         {
93                 array_splice($this->line_items, $line_no, 1);
94         }
95         
96         function order_has_items() 
97         {
98                 return count($this->line_items) != 0;
99         }
100         
101         function clear_items() 
102         {
103         unset($this->line_items);
104                 $this->line_items = array();
105                 
106                 $this->lines_on_order = 0;  
107                 $this->order_no = 0;
108         }
109
110         
111         function any_already_received()
112         {
113                 /* Checks if there have been deliveries or invoiced entered against any of the line items */
114                 if (count($this->line_items) > 0)
115                 {
116                         foreach ($this->line_items as $ordered_items) 
117                         {
118                                 if ($ordered_items->qty_received != 0 || $ordered_items->qty_inv != 0)
119                                 {
120                                         return 1;
121                                 }
122                         }
123                 }
124                 return 0;
125         }
126
127         function some_already_received($line_no)
128         {
129                 /* Checks if there have been deliveries or amounts invoiced against a specific line item */
130                 if (count($this->line_items) > 0)
131                 {
132                         if ($this->line_items[$line_no]->qty_received != 0 || 
133                                 $this->line_items[$line_no]->qty_inv != 0)
134                         {
135                                 return 1;
136                         }
137                 }
138                 return 0;
139         }
140         
141         //
142         //      Returns taxes for PO/GRN.
143         //      $receival=true in purchase receive context.
144         //
145         function get_taxes($shipping_cost=null, $receival=false)
146         {
147                 $items = array();
148                 $prices = array();
149                 if($shipping_cost==null)
150                         $shipping_cost = 0;//$this->freight_cost;
151
152                 foreach ($this->line_items as $ln_itm) {
153                         $items[] = $ln_itm->stock_id;
154                         $prices[] = round($ln_itm->price * $ln_itm->quantity,  user_price_dec());
155                 }
156                 $taxes = get_tax_for_items($this->trans_type, $items, $prices, $shipping_cost,
157                   $this->tax_group_id, $this->tax_included);
158
159         // Adjustment for swiss franken, we always have 5 rappen = 1/20 franken
160             if ($this->curr_code == 'CHF') {
161                         $val = $taxes['1']['Value'];
162                         $val1 = (floatval((intval(round(($val*20),0)))/20));
163                         $taxes['1']['Value'] = $val1;
164                 }
165                 foreach($this->tax_overrides as $id => $value) // add values entered manually
166                 {
167                         $taxes[$id]['Override'] = $value;
168                 }
169                 return $taxes;
170         }
171
172         /*
173                 Returns order value including all taxes
174         */
175         function get_trans_total() {
176                 
177                 $total = 0;
178                 $dec = user_price_dec();
179
180                 foreach ($this->line_items as $ln_itm) {
181                         $items[] = $ln_itm->stock_id;
182                         $value = round($ln_itm->quantity * $ln_itm->price, $dec);
183                         $prices[] =$value;
184                         $total += $value;
185                 }
186
187                 if (!$this->tax_included ) {
188                         $taxes = get_tax_for_items($this->trans_type, $items, $prices, 0, $this->tax_group_id,
189                         $this->tax_included);
190
191                         foreach($taxes as $tax)
192                                 $total += round($tax['Value'], $dec);
193                 }
194                 return $total;
195         }
196
197         function split_line_values()
198         {
199                 // split nominal line values
200                 foreach($this->line_items as $line)
201                         $line->split_item_value($this);
202
203                 // Exact tax values are currently entered as tax totals, so we need to move the differences back on line level.
204                 // currently first item with given tax type will be fixed with the calculated difference
205                 // FIXME: change UI moving tax edit to line level in line edit mode, then this workaround will be obsolete.
206                 foreach($this->get_taxes() as $tax_id => $tax)
207                 {
208                         if ($tax['Value'] != 0 && ($tax['Value'] != $tax['Override']))
209                         {
210                                 foreach($this->line_items as $id => $line)
211                                         if ($line->gl_amounts[0]['tax_type_id'] == $tax_id) // assumed single tax rate on item, so always gl_mount[0] is valid
212                                         {
213                                                 $diff = $tax['Override'] - $tax['Value'];
214                                                 $this->line_items[$id]->gl_amounts[0]['Value'] += $diff;
215                                                 if ($this->vat_category() != VC_NONDEDUCT)
216                                                         $this->line_items[$id]->gl_amounts[0]['Deductible'] += $diff;
217                                                 else
218                                                         $this->line_items[$id]->gl_amounts['Cost'] += $diff;
219                                                  // when supplier uses net prices the price is exact, so don't fix net, still record exact VAT.
220                                                 if ($this->tax_included) 
221                                                 {
222                                                         $this->line_items[$id]->gl_amounts['Net'] -= $diff;
223                                                         $this->line_items[$id]->gl_amounts['Cost'] -= $diff;
224                                                 }
225                                                 break;
226                                         }
227                         }
228                 }
229         }
230
231 } /* end of class defintion */
232
233 class po_line_details 
234 {
235
236         var $line_no;
237         var $po_detail_rec;
238         var $grn_item_id;
239         var $stock_id;
240         var $item_description;
241         var $price;
242         var $units;
243         var $req_del_date;
244
245         var $quantity;          // this document line quantity
246         var $qty_inv;   // quantity already invoiced against this line (all PIs)
247         var $qty_received;      // quantity already received against this line (all GRNs)
248         var $qty_ordered;       // quantity on order (not used on PO entry)
249
250         var $unit_cost;
251         var $descr_editable;
252         var $vat_category;
253
254         function __construct($line_no, $stock_item, $item_descr, $qty, $prc, $uom, $req_del_date, 
255                 $qty_inv, $qty_recd, $qty_ordered=0, $grn_item_id=0)
256         {
257                 /* Constructor function to add a new LineDetail object with passed params */
258                 $this->line_no = $line_no;
259                 $this->stock_id = $stock_item;
260                 $item_row = get_item($stock_item);
261                 if (!$item_row) 
262                         return;
263
264                 $this->descr_editable = $item_row["editable"];
265                 if ($item_descr == null || !$this->descr_editable)
266                         $this->item_description = $item_row["description"];
267                 else
268                         $this->item_description = $item_descr;
269                 $this->quantity = $qty;
270                 $this->req_del_date = $req_del_date;
271                 $this->price = $prc;
272 //              $this->units = $uom;
273                 $this->units = $item_row["units"];
274                 $this->qty_received = $qty_recd;
275                 $this->qty_inv = $qty_inv;
276                 $this->unit_cost =0;
277                 $this->grn_item_id = $grn_item_id;
278                 $this->vat_category = $item_row["vat_category"];
279                 $this->qty_ordered = $qty_ordered;
280         }
281         
282         //
283         // GRN line tax free value.
284         //
285         function taxfree_charge_value($po)
286         {
287                 return get_tax_free_price_for_item($po->trans_type, $this->stock_id, $this->quantity*$this->price,
288                   $po->tax_group_id, $po->tax_included);
289         }
290
291         /*
292                 Splits item value to parts posted to GL.
293         */
294         function split_item_value($cart)
295         {
296         $vat_factor = 1;
297
298                 return $this->gl_amounts = split_item_price($this->stock_id, $this->price*$this->quantity, $cart->tax_group_id, $cart->tax_included, 
299                         ST_SUPPINVOICE, $vat_factor, $cart->tran_date);
300         }
301   
302 }
303