X-Git-Url: https://delta.frontaccounting.com/gitweb/?a=blobdiff_plain;f=includes%2Fui%2Fitems_cart.inc;h=7de50277ff2d9fcc40104c0d0365064c8451f800;hb=c6a369c46e88601885080d716a43a9274a2f1275;hp=6a535725a0188bdb93ef416534b0d0e72a1eb5d8;hpb=5dabbe588fe7f06a6d4f2e6fc1ce074ff5f7e8a4;p=fa-stable.git diff --git a/includes/ui/items_cart.inc b/includes/ui/items_cart.inc index 6a535725..7de50277 100644 --- a/includes/ui/items_cart.inc +++ b/includes/ui/items_cart.inc @@ -1,32 +1,53 @@ . +***********************************************************************/ include_once($path_to_root . "/includes/prefs/sysprefs.inc"); include_once($path_to_root . "/inventory/includes/inventory_db.inc"); class items_cart { - + var $trans_type; var $line_items; var $gl_items; - var $gl_item_count; - var $order_id; - var $editing_item, $deleting_item; - var $from_loc; var $to_loc; var $tran_date; + var $doc_date; + var $event_date; var $transfer_type; var $increase; var $memo_; - var $person_id; var $branch_id; + var $reference; + var $original_amount; + var $currency; + var $rate; + var $source_ref; + var $vat_category; - function items_cart() + var $tax_info; // tax info for the GL transaction + + var $fixed_asset; + + function __construct($type, $trans_no=0) { + $this->trans_type = $type; + $this->order_id = $trans_no; $this->clear_items(); + if (in_array($type, array(ST_LOCTRANSFER, ST_INVADJUST, ST_COSTUPDATE, ST_MANUISSUE, ST_MANURECEIVE, ST_JOURNAL))) + $this->currency = get_company_pref('curr_default'); + $this->rate = 1; } // --------------- line item functions @@ -43,7 +64,7 @@ class items_cart else { // shouldn't come here under normal circumstances - display_db_error("unexpected - adding an invalid item or null quantity", "", true); + display_error("unexpected - adding an invalid item or null quantity", "", true); } return false; @@ -66,7 +87,7 @@ class items_cart function remove_from_cart($line_no) { - unset($this->line_items[$line_no]); + array_splice($this->line_items, $line_no, 1); } function count_items() @@ -76,53 +97,78 @@ class items_cart function check_qoh($location, $date_, $reverse=false) { - foreach ($this->line_items as $line_no => $line_item) - { - $item_ret = $line_item->check_qoh($location, $date_, $reverse); - if ($item_ret != null) - return $line_no; + global $SysPrefs; + + $low_stock = array(); + + if (!$SysPrefs->allow_negative_stock()) + { + foreach ($this->line_items as $line_no => $line_item) + if (has_stock_holding($line_item->mb_flag) || is_fixed_asset($line_item->mb_flag)) + { + $quantity = $line_item->quantity; + if ($reverse) + $quantity = -$line_item->quantity; + + if ($quantity >= 0) + continue; + + if (check_negative_stock($line_item->stock_id, $quantity, $location, $date_)) + $low_stock[] = $line_item->stock_id; + } } + return $low_stock; } // ----------- GL item functions - function add_gl_item($code_id, $dimension_id, $dimension2_id, $amount, $reference, $description=null) + function add_gl_item($code_id, $dimension_id, $dimension2_id, $amount, $memo='', $act_descr=null, $person_id=null, $date=null) { if (isset($code_id) && $code_id != "" && isset($amount) && isset($dimension_id) && isset($dimension2_id)) { - $this->gl_items[$this->gl_item_count] = new gl_item($this->gl_item_count, - $code_id, $dimension_id, $dimension2_id, $amount, $reference, $description); - $this->gl_item_count++; + $this->gl_items[] = new gl_item($code_id, $dimension_id, $dimension2_id, $amount, $memo, $act_descr, $person_id, $date); return true; } else { // shouldn't come here under normal circumstances - display_db_error("unexpected - adding an invalid item or null quantity", "", true); + display_error("unexpected - invalid parameters in add_gl_item($code_id, $dimension_id, $dimension2_id, $amount,...)", "", true); } return false; } - function update_gl_item($index, $dimension_id, $dimension2_id, $amount, $reference, $description=null) + function update_gl_item($index, $code_id, $dimension_id, $dimension2_id, $amount, $memo='', $act_descr=null, $person_id=null) { - $this->gl_items[$index]->index = $index; + $this->gl_items[$index]->code_id = $code_id; + $this->gl_items[$index]->person_id = $person_id; + + $gl_type = is_subledger_account($code_id); + if ($person_id != null && $gl_type) + { + $this->gl_items[$index]->person_type_id = $gl_type > 0 ? PT_CUSTOMER : PT_SUPPLIER; + $data = get_subaccount_data($code_id, $person_id); + $this->gl_items[$index]->person_name = $data['name']; + $this->gl_items[$index]->branch_id = $data['id']; + } else + { + $this->gl_items[$index]->person_type_id = $this->gl_items[$index]->person_name = ''; + } $this->gl_items[$index]->dimension_id = $dimension_id; $this->gl_items[$index]->dimension2_id = $dimension2_id; $this->gl_items[$index]->amount = $amount; - $this->gl_items[$index]->reference = $reference; - if ($description != null) - $this->gl_items[$index]->description = $description; + $this->gl_items[$index]->reference = $memo; + if ($act_descr == null) + $this->gl_items[$index]->description = get_gl_account_name($code_id); + else + $this->gl_items[$index]->description = $act_descr; } function remove_gl_item($index) { - if (isset($index)) - { - unset($this->gl_items[$index]); - } + array_splice($this->gl_items, $index, 1); } function count_gl_items() @@ -169,9 +215,241 @@ class items_cart unset($this->gl_items); $this->gl_items = array(); - $this->gl_item_count = 1; } + // + // Check if cart contains virtual subaccount (AP/AR) postings + // + function has_sub_accounts() + { + foreach ($this->gl_items as $gl_item) + { + if (is_subledger_account($gl_item->code_id)) + return true; + } + return false; + } + + // + // Check if cart contains postings to tax accounts + // + function has_taxes() + { + foreach ($this->gl_items as $gl_item) + { + if (is_tax_account($gl_item->code_id)) + return true; + } + return false; + } + + /* + Collect tax info from the GL transaction lines and return as array of values: + 'tax_date' - tax date + 'tax_group' - related counterparty tax group + 'tax_category' - tax category (not set for now) + 'net_amount' - tax amounts array indexed by tax type id + 'tax_in', 'tax_out' - tax amounts array indexed by tax type id + 'tax_reg' - tax register used + */ + function collect_tax_info() + { + $tax_info = array(); + $subledger_sum = $net_sum = 0; + + $tax_info['tax_date'] = $this->tran_date; + $vat_percent = get_company_pref('partial_vat_percent'); + $factor = $vat_percent && ($this->vat_category == VC_PARTIAL) ? $vat_percent/100: 1; + + foreach($this->gl_items as $gl) + { + if ($person_type = is_subledger_account($gl->code_id)) + { + $tax_info['person_type'] = $person_type < 0 ? PT_SUPPLIER : PT_CUSTOMER; + $tax_info['person_id'] = $gl->person_id; + + if ($tax_info['person_type'] == PT_CUSTOMER) + { + $branch = get_default_branch($gl->person_id); + $tax_info['tax_group'] = $branch['tax_group_id']; + } else { + $supplier = get_supplier($gl->person_id); + $tax_info['tax_group'] = $supplier['tax_group_id']; + } + $subledger_sum += $gl->amount; + } elseif ($tax_id = is_tax_account($gl->code_id)) + { + $tax_type = get_tax_type($tax_id); + if ($gl->code_id == $tax_type['purchasing_gl_code']) { + if (!isset($tax_info['tax_in'][$tax_id])) + $tax_info['tax_in'][$tax_id] = 0; + $tax_info['tax_in'][$tax_id] += $gl->amount; + $tax_info['tax_reg'] = TR_INPUT; + } else { + if (!isset($tax_info['tax_out'][$tax_id])) + $tax_info['tax_out'][$tax_id] = 0; + $tax_info['tax_out'][$tax_id] -= $gl->amount; + if (!isset($tax_info['tax_reg'])) // TR_INPUT has priority (EU are posted on both accounts) + $tax_info['tax_reg'] = TR_OUTPUT; + } + if ($tax_type['rate']) + { + // assume transaction adjustment for negative tax in/out + $sign = (@$tax_info['tax_in'][$tax_id] < 0 || @$tax_info['tax_out'][$tax_id] < 0) ? -1 : 1; + // we can have both input and output tax postings in some cases like intra-EU trade. + // so just calculate net_amount from the higher in/out tax + $tax_info['net_amount'][$tax_id] + = $sign*round2(max(abs(@$tax_info['tax_in'][$tax_id]), abs(@$tax_info['tax_out'][$tax_id]))/$tax_type['rate']*100, user_price_dec())/$factor; + + } + } else + $net_sum += $gl->amount; + } + // if no tax amount posted guess register type from person_type used (e.g. export invoice) + if (!isset($tax_info['tax_reg']) && isset($tax_info['person_type'])) + $tax_info['tax_reg'] = $tax_info['person_type']==PT_CUSTOMER ? TR_OUTPUT : TR_INPUT; + + if (count_array(@$tax_info['net_amount'])) // guess exempt sales/purchase if any tax has been found + { + $ex_net = abs($net_sum) - @array_sum($tax_info['net_amount']); + if ($ex_net != 0) + $tax_info['net_amount_ex'] = $ex_net; + } + + return $tax_info; + } + + function set_currency($curr, $rate=0) + { + $this->currency = $curr; + $this->rate = $rate; + } + + /* + Reduce number of necessary gl posting lines. + */ + function reduce_gl() + { + /* reduce additional postings */ + $codes = array(); + foreach($this->gl_items as $n => $gl) + { + $prev = @$codes[$gl->code_id][$gl->person_id][$gl->dimension_id][$gl->dimension2_id][$gl->reference]; + if (isset($prev)) { // add amount to previous line for the same gl_code dims and memo + $this->gl_items[$prev]->amount += $gl->amount; + if ($this->gl_items[$prev]->amount == 0) // discard if overall amount==0 + { + unset($this->gl_items[$prev], $codes[$gl->code_id][$gl->person_id][$gl->dimension_id][$gl->dimension2_id][$gl->reference]); + } + unset($this->gl_items[$n]); + } else + $codes[$gl->code_id][$gl->person_id][$gl->dimension_id][$gl->dimension2_id][$gl->reference] = $n; + } + } + /* + Write transaction GL postings, creating tax records and updating AP/AR/bank ledger if needed. + */ + function write_gl($check_balance = true) + { + $delta = $this->gl_items_total(); + if ($check_balance && floatcmp($delta, 0) !=0) + { + $this->add_gl_item(get_company_pref($delta>0 ? 'rounding_db_act' : 'rounding_cr_act'), + 0, 0, -$delta, ''); + error_log(sprintf( _("Rounding error %s encountered for trans_type:%s,trans_no:%s"), $delta, $this->trans_type, $this->order_id)); + } + + $bank_trans = $supp_trans = $cust_trans = array(); + $total_gl = 0; + foreach($this->gl_items as $gl) + { + if (!isset($gl->date)) + $gl->date = $this->tran_date; + + $total_gl += add_gl_trans($this->trans_type, $this->order_id, $gl->date, $gl->code_id, $gl->dimension_id, $gl->dimension2_id, + $gl->reference, $gl->amount, $this->currency, $gl->person_type_id, $gl->person_id, "", $this->rate); + + // post to first found bank account using given gl acount code. + $is_bank_to = is_bank_account($gl->code_id); + if ($is_bank_to && (get_bank_account_currency($is_bank_to) == $this->currency)) // do not register exchange variations in bank trans + { + if (!isset($bank_trans[$is_bank_to])) + $bank_trans[$is_bank_to] = 0; + + $bank_trans[$is_bank_to] += $gl->amount; + } elseif ($gl->person_id) + { + $home_currency = get_company_currency(); + // collect per counterparty amounts (in case more than one posting was done to the account), + // do not post exchange variations to AR/AP (journal in not customer/supplier currency) + if ($gl->person_type_id==PT_SUPPLIER && (get_supplier_currency($gl->person_id) == $this->currency || $this->currency != $home_currency)) + $supp_trans[$gl->person_id] = @$supp_trans[$gl->person_id] + $gl->amount; + elseif ($gl->person_type_id==PT_CUSTOMER && (get_customer_currency(null, $gl->branch_id) == $this->currency || $this->currency != $home_currency)) + $cust_trans[$gl->branch_id] = @$cust_trans[$gl->branch_id] + $gl->amount; + } + + } + // post currency roundings if any + if ($check_balance && floatcmp($total_gl, 0)) + add_gl_trans($this->trans_type, $this->order_id, $this->tran_date, + get_company_pref($total_gl>0 ? 'rounding_db_act' : 'rounding_cr_act'), 0, 0, _('Exchange rate roundings'), -$total_gl); + + // update bank ledger if used + foreach($bank_trans as $bank_id => $amount) + add_bank_trans($this->trans_type, $this->order_id, $bank_id, $this->reference, + $this->tran_date, $amount, 0, "", $this->currency, + "Cannot insert a destination bank transaction"); + + // add AP/AR for journal transaction + if ($this->trans_type == ST_JOURNAL) + { + // update AR + foreach($cust_trans as $branch_id => $amount) + if (floatcmp($amount, 0)) + write_cust_journal($this->trans_type, $this->order_id, $branch_id, $this->tran_date, + $this->reference, $amount, $this->rate); + // update AP + foreach($supp_trans as $supp_id => $amount) + if (floatcmp($amount, 0)) + write_supp_journal($this->trans_type, $this->order_id, $supp_id, $this->tran_date, + $this->reference, -$amount, $this->rate, $this->source_ref); + } + + // generate tax records for journal transaction + if ($this->trans_type == ST_JOURNAL && is_array($this->tax_info)) + { + foreach($this->tax_info['net_amount'] as $tax_id => $net) + { + if (!$net) + continue; + + // in EU VAT system intra-community goods aquisition is posted to both purchasing and sales tax accounts, + // but included only in purchase register. To avoid double registering ELSE is used below! + if (isset($this->tax_info['tax_in'][$tax_id])) + { + $tax = $this->tax_info['tax_in'][$tax_id]; + $reg = TR_INPUT; + } + elseif (isset($this->tax_info['tax_out'][$tax_id])) + { + $tax = $this->tax_info['tax_out'][$tax_id]; + $reg = TR_OUTPUT; + } + elseif (isset($this->tax_info['tax_reg'])) // e.g. export + { + $tax = 0; + $reg = $this->tax_info['tax_reg']; + } else + continue; + + $tax_nominal = $this->tax_info['rate'][$tax_id]/100*$net; + add_trans_tax_details($this->trans_type, $this->order_id, + $tax_id, $this->tax_info['rate'][$tax_id], 0, $tax_nominal, $net, $this->rate, + $this->tran_date, + $this->source_ref, $reg); + } + } + } } //-------------------------------------------------------------------------------------------- @@ -187,12 +465,12 @@ class line_item var $price; var $standard_cost; - function line_item ($stock_id, $qty, $standard_cost=null, $description=null) + function __construct($stock_id, $qty, $standard_cost=null, $description=null) { $item_row = get_item($stock_id); if ($item_row == null) - display_db_error("invalid item added to order : $stock_id", ""); + display_error("invalid item added to order : $stock_id", ""); $this->mb_flag = $item_row["mb_flag"]; $this->units = $item_row["units"]; @@ -203,7 +481,7 @@ class line_item $this->item_description = $description; if ($standard_cost == null) - $this->standard_cost = $item_row["actual_cost"]; + $this->standard_cost = $item_row["purchase_cost"]; else $this->standard_cost = $standard_cost; @@ -212,30 +490,6 @@ class line_item //$this->price = $price; $this->price = 0; } - - function check_qoh($location, $date_, $reverse) - { - if (!sys_prefs::allow_negative_stock()) - { - if (has_stock_holding($this->mb_flag)) - { - $quantity = $this->quantity; - if ($reverse) - $quantity = -$this->quantity; - - if ($quantity >= 0) - return null; - - $qoh = get_qoh_on_date($this->stock_id, $location, $date_); - if ($quantity + $qoh < 0) - { - return $this; - } - } - } - - return null; - } } //--------------------------------------------------------------------------------------- @@ -243,33 +497,42 @@ class line_item class gl_item { - var $index; var $code_id; var $dimension_id; var $dimension2_id; var $amount; var $reference; var $description; + var $person_id; + var $person_type_id; + var $person_name; + var $branch_id; + var $date; - function gl_item($index, $code_id, $dimension_id, $dimension2_id, $amount, $reference, - $description=null) + function __construct($code_id=null, $dimension_id=0, $dimension2_id=0, $amount=0, $memo='', + $act_descr=null, $person_id=null, $date=null) { //echo "adding $index, $code_id, $dimension_id, $amount, $reference
"; - if ($description == null) + if ($act_descr == null && $code_id) $this->description = get_gl_account_name($code_id); else - $this->description = $description; + $this->description = $act_descr; - $this->index = $index; $this->code_id = $code_id; + $this->person_id = $person_id; + $gl_type = is_subledger_account($code_id); + if ($person_id != null && $gl_type) + { + $this->person_type_id = $gl_type > 0 ? PT_CUSTOMER : PT_SUPPLIER; + $data = get_subaccount_data($code_id, $person_id); + $this->person_name = $data['name']; + $this->branch_id = $data['id']; + } $this->dimension_id = $dimension_id; $this->dimension2_id = $dimension2_id; - $this->amount = $amount; - $this->reference = $reference; + $this->amount = round2($amount, user_price_dec()); + $this->reference = $memo; + $this->date = $date; } } - -//--------------------------------------------------------------------------------------- - -?>