NEW Introduce cost price on product.

This commit is contained in:
Laurent Destailleur
2015-11-30 21:20:45 +01:00
parent ebe4867ab1
commit de730c9762
10 changed files with 83 additions and 30 deletions

View File

@@ -77,7 +77,7 @@ class Form
* @param string $preselected Name of Value to show/edit (not used in this function)
* @param object $object Object
* @param boolean $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field.
* @param string $typeofdata Type of data ('string' by default, 'email', 'numeric:99', 'text' or 'textarea:rows:cols', 'day' or 'datepicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...)
* @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'day' or 'datepicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...)
* @param string $moreparam More param to add on a href URL
* @return string HTML edit field
*/
@@ -122,7 +122,7 @@ class Form
* @param string $value Value to show/edit
* @param object $object Object
* @param boolean $perm Permission to allow button to edit parameter
* @param string $typeofdata Type of data ('string' by default, 'amount', 'email', 'numeric:99', 'text' or 'textarea:rows:cols', 'day' or 'datepicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select:xxx'...)
* @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'day' or 'datepicker', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select:xxx'...)
* @param string $editvalue When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of value). Use '' to use same than $value
* @param object $extObject External object
* @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
@@ -154,11 +154,16 @@ class Form
$ret.='<input type="hidden" name="id" value="'.$object->id.'">';
$ret.='<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
$ret.='<tr><td>';
if (preg_match('/^(string|email|numeric|amount)/',$typeofdata))
if (preg_match('/^(string|email)/',$typeofdata))
{
$tmp=explode(':',$typeofdata);
$ret.='<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue?$editvalue:$value).'"'.($tmp[1]?' size="'.$tmp[1].'"':'').'>';
}
else if (preg_match('/^(numeric|amount)/',$typeofdata))
{
$tmp=explode(':',$typeofdata);
$ret.='<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.price(price2num($editvalue?$editvalue:$value)).'"'.($tmp[1]?' size="'.$tmp[1].'"':'').'>';
}
else if (preg_match('/^text/',$typeofdata) || preg_match('/^note/',$typeofdata))
{
$tmp=explode(':',$typeofdata);
@@ -203,8 +208,8 @@ class Form
}
else
{
if ($typeofdata == 'email') $ret.=dol_print_email($value,0,0,0,0,1);
elseif ($typeofdata == 'amount') $ret.=($value != '' ? price($value,'',$langs,0,-1,-1,$conf->currency) : '');
if (preg_match('/^(email)/',$typeofdata)) $ret.=dol_print_email($value,0,0,0,0,1);
elseif (preg_match('/^(amount|numeric)/',$typeofdata)) $ret.=($value != '' ? price($value,'',$langs,0,-1,-1,$conf->currency) : '');
elseif (preg_match('/^text/',$typeofdata) || preg_match('/^note/',$typeofdata)) $ret.=dol_htmlentitiesbr($value);
elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret.=dol_print_date($value,'day');
elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret.=dol_print_date($value,'dayhour');

View File

@@ -1,5 +1,5 @@
<?php
/* Copyright (C) 2006-2008 Laurent Destailleur <eldy@users.sourceforge.net>
/* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2009-2010 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
@@ -46,14 +46,16 @@ function product_prepare_head($object)
$h++;
$head[$h][0] = DOL_URL_ROOT."/product/price.php?id=".$object->id;
$head[$h][1] = $langs->trans("CustomerPrices");
$head[$h][1] = $langs->trans("SellingPrices");
$head[$h][2] = 'price';
$h++;
if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire)
if ((! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire)
|| (! empty($conf->margin->enabled) && $user->rights->margin->liretous)
)
{
$head[$h][0] = DOL_URL_ROOT."/product/fournisseurs.php?id=".$object->id;
$head[$h][1] = $langs->trans("SuppliersPrices");
$head[$h][1] = $langs->trans("BuyingPrices");
$head[$h][2] = 'suppliers';
$h++;
}

View File

@@ -353,7 +353,7 @@ class ProductFournisseur extends Product
function fetch_product_fournisseur_price($rowid, $ignore_expression = 0)
{
$sql = "SELECT pfp.rowid, pfp.price, pfp.quantity, pfp.unitprice, pfp.remise_percent, pfp.remise, pfp.tva_tx, pfp.fk_availability,";
$sql.= " pfp.fk_soc, pfp.ref_fourn, pfp.fk_product, pfp.charges, pfp.unitcharges, pfp.fk_supplier_price_expression, pfp.delivery_time_days"; // , pfp.recuperableonly as fourn_tva_npr"; FIXME this field not exist in llx_product_fournisseur_price
$sql.= " pfp.fk_soc, pfp.ref_fourn, pfp.fk_product, pfp.charges, pfp.cost_price, pfp.unitcharges, pfp.fk_supplier_price_expression, pfp.delivery_time_days"; // , pfp.recuperableonly as fourn_tva_npr"; FIXME this field not exist in llx_product_fournisseur_price
$sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp";
$sql.= " WHERE pfp.rowid = ".$rowid;
@@ -368,12 +368,12 @@ class ProductFournisseur extends Product
$this->fourn_ref = $obj->ref_fourn; // deprecated
$this->ref_supplier = $obj->ref_fourn;
$this->fourn_price = $obj->price;
$this->fourn_charges = $obj->charges;
$this->fourn_charges = $obj->charges; // deprecated
$this->fourn_qty = $obj->quantity;
$this->fourn_remise_percent = $obj->remise_percent;
$this->fourn_remise = $obj->remise;
$this->fourn_unitprice = $obj->unitprice;
$this->fourn_unitcharges = $obj->unitcharges;
$this->fourn_unitcharges = $obj->unitcharges; // deprecated
$this->fourn_tva_tx = $obj->tva_tx;
$this->product_id = $obj->fk_product; // deprecated
$this->fk_product = $obj->fk_product;
@@ -456,9 +456,9 @@ class ProductFournisseur extends Product
$prodfourn->fourn_qty = $record["quantity"];
$prodfourn->fourn_remise_percent = $record["remise_percent"];
$prodfourn->fourn_remise = $record["remise"];
$prodfourn->fourn_unitprice = $record["unitprice"];
$prodfourn->fourn_charges = $record["charges"];
$prodfourn->fourn_unitcharges = $record["unitcharges"];
$prodfourn->fourn_unitprice = $record["unitprice"];
$prodfourn->fourn_charges = $record["charges"]; // deprecated
$prodfourn->fourn_unitcharges = $record["unitcharges"]; // deprecated
$prodfourn->fourn_tva_tx = $record["tva_tx"];
$prodfourn->fourn_id = $record["fourn_id"];
$prodfourn->fourn_name = $record["supplier_name"];
@@ -591,8 +591,8 @@ class ProductFournisseur extends Product
$this->fourn_remise_percent = $record["remise_percent"];
$this->fourn_remise = $record["remise"];
$this->fourn_unitprice = $fourn_unitprice;
$this->fourn_charges = $record["charges"];
$this->fourn_unitcharges = $record["unitcharges"];
$this->fourn_charges = $record["charges"]; // deprecated
$this->fourn_unitcharges = $record["unitcharges"]; // deprecated
$this->fourn_tva_tx = $record["tva_tx"];
$this->fourn_id = $record["fourn_id"];
$this->fourn_name = $record["supplier_name"];

View File

@@ -97,6 +97,8 @@ ALTER TABLE llx_commande ADD COLUMN fk_warehouse integer DEFAULT NULL AFTER fk_s
ALTER TABLE llx_commande_fournisseur ADD COLUMN billed smallint DEFAULT 0 AFTER fk_statut;
ALTER TABLE llx_commande_fournisseur ADD INDEX billed (billed);
ALTER TABLE llx_product ADD COLUMN cost_price double(24,8) DEFAULT NULL;
ALTER TABLE llx_ecm_directories MODIFY COLUMN fullpath varchar(750);
ALTER TABLE llx_ecm_directories DROP INDEX idx_ecm_directories;
ALTER TABLE llx_ecm_directories ADD UNIQUE INDEX uk_ecm_directories (label, fk_parent, entity);

View File

@@ -44,8 +44,9 @@ create table llx_product
price_min double(24,8) DEFAULT 0,
price_min_ttc double(24,8) DEFAULT 0,
price_base_type varchar(3) DEFAULT 'HT',
tva_tx double(6,3), -- Default VAT rate of product
recuperableonly integer NOT NULL DEFAULT '0', -- French NPR VAT
cost_price double(24,8) DEFAULT NULL, -- Cost price without tax. Can be used for margin calculation.
tva_tx double(6,3), -- Default VAT rate of product
recuperableonly integer NOT NULL DEFAULT '0', -- French NPR VAT
localtax1_tx double(6,3) DEFAULT 0, -- Spanish local VAT 1
localtax2_tx double(6,3) DEFAULT 0, -- Spanish local VAT 2
fk_user_author integer DEFAULT NULL, -- user making creation

View File

@@ -34,12 +34,12 @@ create table llx_product_fournisseur_price
remise_percent double NOT NULL DEFAULT 0,
remise double NOT NULL DEFAULT 0,
unitprice double(24,8) DEFAULT 0,
charges double(24,8) DEFAULT 0,
unitcharges double(24,8) DEFAULT 0,
charges double(24,8) DEFAULT 0, -- to store transport cost. Constant PRODUCT_CHARGES must be set to see it.
unitcharges double(24,8) DEFAULT 0, -- deprecated
tva_tx double(6,3) NOT NULL,
info_bits integer NOT NULL DEFAULT 0,
fk_user integer,
fk_supplier_price_expression integer, -- Link to the rule for dynamic price calculation
import_key varchar(14), -- Import key
fk_supplier_price_expression integer, -- Link to the rule for dynamic price calculation
import_key varchar(14), -- Import key
delivery_time_days integer
)ENGINE=innodb;

View File

@@ -76,6 +76,8 @@ SellingPriceHT=Selling price (net of tax)
SellingPriceTTC=Selling price (inc. tax)
PublicPrice=Public price
CurrentPrice=Current price
CostPriceDescription=This price (net of tax) can be used to store the average amount this product cost to your company. It may be any price you calculate yourself, for example from the average buying price plus average transportation and acquiring cost.
CostPriceUsage=In a future version, this value could be used for margin calculation.
NewPrice=New price
MinPrice=Min. selling price
MinPriceHT=Min. selling price (net of tax)
@@ -190,6 +192,8 @@ ClonePricesProduct=Clone main informations and prices
CloneCompositionProduct=Clone packaged product/service
ProductIsUsed=This product is used
NewRefForClone=Ref. of new product/service
SellingPrices=Selling prices
BuyingPrices=Buying prices
CustomerPrices=Customer prices
SuppliersPrices=Supplier prices
SuppliersPricesOfProductsOrServices=Supplier prices (of products or services)

View File

@@ -1563,7 +1563,7 @@ class Product extends CommonObject
}
$sql = "SELECT rowid, ref, ref_ext, label, description, url, note, customcode, fk_country, price, price_ttc,";
$sql.= " price_min, price_min_ttc, price_base_type, tva_tx, recuperableonly as tva_npr, localtax1_tx, localtax2_tx, tosell,";
$sql.= " price_min, price_min_ttc, price_base_type, cost_price, tva_tx, recuperableonly as tva_npr, localtax1_tx, localtax2_tx, tosell,";
$sql.= " tobuy, fk_product_type, duration, seuil_stock_alerte, canvas,";
$sql.= " weight, weight_units, length, length_units, surface, surface_units, volume, volume_units, barcode, fk_barcode_type, finished,";
$sql.= " accountancy_code_buy, accountancy_code_sell, stock, pmp,";
@@ -1606,6 +1606,7 @@ class Product extends CommonObject
$this->price_min = $obj->price_min;
$this->price_min_ttc = $obj->price_min_ttc;
$this->price_base_type = $obj->price_base_type;
$this->cost_price = $obj->cost_price;
$this->tva_tx = $obj->tva_tx;
//! French VAT NPR
$this->tva_npr = $obj->tva_npr;

View File

@@ -46,6 +46,7 @@ $rowid=GETPOST('rowid','int');
$action=GETPOST('action', 'alpha');
$cancel=GETPOST('cancel', 'alpha');
$socid=GETPOST('socid', 'int');
$cost_price=GETPOST('cost_price', 'int');
$backtopage=GETPOST('backtopage','alpha');
$error=0;
@@ -91,17 +92,37 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e
if (empty($reshook))
{
if ($action == 'setcost_price')
{
if ($id)
{
$result=$object->fetch($id);
$result=$object->setValueFrom('cost_price', price2num($cost_price));
if ($result > 0)
{
$object->cost_price = price2num($cost_price);
setEventMessage($langs->trans("RecordSaved"));
}
else
{
$error++;
setEventMessages($object->error, $object->errors, 'errors');
}
}
$action='';
}
if ($action == 'remove_pf')
{
if ($rowid)
if ($rowid) // id of product supplier price to remove
{
$action = '';
$result=$product->remove_product_fournisseur_price($rowid);
$result=$object->remove_product_fournisseur_price($rowid);
if($result > 0){
setEventMessage($langs->trans("PriceRemoved"));
}else{
$error++;
setEventMessages($product->error, $product->errors, 'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
@@ -282,6 +303,17 @@ if ($id > 0 || $ref)
}
print '</td></tr>';
// Cost price. Can be used for margin module for option "calculate margin on explicit cost price
// Accountancy sell code
print '<tr><td>';
$textdesc =$langs->trans("CostPriceDescription");
$textdesc.="<br>".$langs->trans("CostPriceUsage");
$text=$form->textwithpicto($langs->trans("CostPrice"), $textdesc, 1, 'help', '');
print $form->editfieldkey($text,'cost_price',$object->cost_price,$object,$user->rights->produit->creer||$user->rights->service->creer,'amount:6');
print '</td><td colspan="2">';
print $form->editfieldval($text,'cost_price',$object->cost_price,$object,$user->rights->produit->creer||$user->rights->service->creer,'amount:6');
print '</td></tr>';
print '</table>';
print '</div>';
@@ -463,7 +495,7 @@ if ($id > 0 || $ref)
print '<td><input class="flat" name="delivery_time_days" size="4" value="'.($rowid ? $object->delivery_time_days : '').'">&nbsp;'.$langs->trans('days').'</td>';
print '</tr>';
// Charges ????
// Option to define a transport cost on supplier price
if ($conf->global->PRODUCT_CHARGES)
{
if (! empty($conf->margin->enabled))

View File

@@ -1016,14 +1016,20 @@ if (($action == 'create') || ($action == 'adduserldap'))
$langs->load("salaries");
// THM
print '<tr><td>'.$langs->trans("THM").'</td>';
print '<tr><td>';
$text=$langs->trans("THM");
print $form->textwithpicto($text, $langs->trans("THMDescription"), 1, 'help', 'classthm');
print '</td>';
print '<td>';
print '<input size="8" type="text" name="thm" value="'.GETPOST('thm').'">';
print '</td>';
print "</tr>\n";
// TJM
print '<tr><td>'.$langs->trans("TJM").'</td>';
print '<tr><td>';
$text=$langs->trans("TJM");
print $form->textwithpicto($text, $langs->trans("TJMDescription"), 1, 'help', 'classtjm');
print '</td>';
print '<td>';
print '<input size="8" type="text" name="tjm" value="'.GETPOST('tjm').'">';
print '</td>';