Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions Core/Lib/CostPriceTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ protected static function updateAveragePrice(Variante $variant): void
Where::gt('neto', 0),
];
foreach (ProductoProveedor::all($where, ['actualizado' => 'DESC'], 0, 0) as $prod) {
$prices[] = $prod->neto;
$prices[] = static::calcularCosteProveedor($prod);
}

$newCost = empty($prices) ? 0.0 : array_sum($prices) / count($prices);
Expand All @@ -158,7 +158,7 @@ protected static function updateLastPrice(Variante $variant): void
Where::gt('neto', 0),
];
foreach (ProductoProveedor::all($where, ['actualizado' => 'DESC'], 0, 1) as $prod) {
$variant->coste = round($prod->neto, Producto::ROUND_DECIMALS);
$variant->coste = round(static::calcularCosteProveedor($prod), Producto::ROUND_DECIMALS);
$variant->save();
break;
}
Expand All @@ -176,9 +176,19 @@ protected static function updateHighPrice(Variante $variant): void
Where::gt('neto', 0),
];
foreach (ProductoProveedor::all($where, ['precio' => 'DESC'], 0, 1) as $prod) {
$variant->coste = round($prod->neto, Producto::ROUND_DECIMALS);
$variant->coste = round(static::calcularCosteProveedor($prod), Producto::ROUND_DECIMALS);
$variant->save();
break;
}
}

protected static function calcularCosteProveedor(ProductoProveedor $productoProveedor): float
{
return match (Tools::settings('default', 'calculocosteproveedor', 'neto')) {
'precio' => $productoProveedor->precio,
'netomasextra' => $productoProveedor->neto + $productoProveedor->precioextra,
'preciomasextra' => $productoProveedor->precio + $productoProveedor->precioextra,
default => $productoProveedor->neto,
};
}
}
6 changes: 5 additions & 1 deletion Core/Model/ProductoProveedor.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class ProductoProveedor extends ModelClass
/** @var float */
public $precio;

/** @var float */
public $precioextra;

/** @var string */
public $referencia;

Expand Down Expand Up @@ -113,6 +116,7 @@ public function clear(): void
$this->neto = 0.0;
$this->netoeuros = 0.0;
$this->precio = 0.0;
$this->precioextra = 0.0;
$this->stock = 0.0;
}

Expand Down Expand Up @@ -217,7 +221,7 @@ protected function onInsert(): void
*/
protected function onUpdate(): void
{
if ($this->isDirty('neto')) {
if ($this->isDirty('neto') || $this->isDirty('precioextra')) {
CostPriceTools::update($this->getVariant());
}

Expand Down
7 changes: 6 additions & 1 deletion Core/Table/productosprov.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
<name>precio</name>
<type>double precision</type>
</column>
<column>
<name>precioextra</name>
<type>double precision</type>
<default>0</default>
</column>
<column>
<name>referencia</name>
<type>character varying(30)</type>
Expand Down Expand Up @@ -83,4 +88,4 @@
<name>uniq_productosprov</name>
<type>UNIQUE (codproveedor,refproveedor,referencia,coddivisa)</type>
</constraint>
</table>
</table>
17 changes: 10 additions & 7 deletions Core/XMLView/EditProductoProveedor.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,29 @@
<column name="price" order="130">
<widget type="money" fieldname="precio"/>
</column>
<column name="dto" order="140">
<column name="precioextra" order="140">
<widget type="money" fieldname="precioextra"/>
</column>
<column name="dto" order="150">
<widget type="percentage" fieldname="dtopor"/>
</column>
<column name="dto-2" display="none" order="150">
<column name="dto-2" display="none" order="160">
<widget type="percentage" fieldname="dtopor2"/>
</column>
<column name="net" order="160">
<column name="net" order="170">
<widget type="money" fieldname="neto" readonly="true"/>
</column>
<column name="stock" display="none" order="170">
<column name="stock" display="none" order="180">
<widget type="number" fieldname="stock"/>
</column>
<column name="update-time" display="none" order="180">
<column name="update-time" display="none" order="190">
<widget type="datetime" fieldname="actualizado" readonly="true"/>
</column>
<column name="currency" order="190">
<column name="currency" order="200">
<widget type="select" fieldname="coddivisa" onclick="EditDivisa" readonly="dinamic">
<values source="divisas" fieldcode="coddivisa" fieldtitle="descripcion"/>
</widget>
</column>
</group>
</columns>
</view>
</view>
15 changes: 9 additions & 6 deletions Core/XMLView/ListProductoProveedor.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,23 @@
<column name="price" display="none" order="140">
<widget type="money" fieldname="precio"/>
</column>
<column name="dto" display="none" order="150">
<column name="precioextra" display="none" order="150">
<widget type="money" fieldname="precioextra"/>
</column>
<column name="dto" display="none" order="160">
<widget type="number" fieldname="dtopor"/>
</column>
<column name="dto-2" display="none" order="160">
<column name="dto-2" display="none" order="170">
<widget type="number" fieldname="dtopor2"/>
</column>
<column name="net" display="right" order="170">
<column name="net" display="right" order="180">
<widget type="money" fieldname="neto"/>
</column>
<column name="stock" display="none" order="180">
<column name="stock" display="none" order="190">
<widget type="number" fieldname="stock"/>
</column>
<column name="update-time" display="right" order="190">
<column name="update-time" display="right" order="200">
<widget type="datetime" fieldname="actualizado"/>
</column>
</columns>
</view>
</view>
14 changes: 11 additions & 3 deletions Core/XMLView/SettingsDefault.xml
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,18 @@
<values title="high-purchase-price">high-price</values>
</widget>
</column>
<column name="update-supplier-prices" numcolumns="3" order="110">
<column name="calculocosteproveedor" numcolumns="3" order="110">
<widget type="select" fieldname="calculocosteproveedor" translate="true">
<values title="neto">neto</values>
<values title="precio">precio</values>
<values title="netomasextra">netomasextra</values>
<values title="preciomasextra">preciomasextra</values>
</widget>
</column>
<column name="update-supplier-prices" numcolumns="3" order="120">
<widget type="checkbox" fieldname="updatesupplierprices"/>
</column>
<column name="allow-sale-without-stock-n" numcolumns="6" order="120">
<column name="allow-sale-without-stock-n" numcolumns="3" order="130">
<widget type="checkbox" fieldname="ventasinstock"/>
</column>
</group>
Expand Down Expand Up @@ -188,4 +196,4 @@
</column>
</group>
</columns>
</view>
</view>
60 changes: 59 additions & 1 deletion Test/Core/Lib/CostPriceToolsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,62 @@ public function testLastPriceLeavesCosteUnchangedWhenAllZero(): void
$this->assertEquals(7.5, (float)$variant->coste, 'sin filas con neto > 0 el coste anterior debe preservarse');
}

public function testCalculoCosteProveedor(): void
{
$producto = $this->createProduct();
$variante = $producto->getVariants()[0];

$this->createSupplierProduct($producto, 100.0, '2024-01-01 00:00:00', 10.0, 5.0);
Tools::settingsSet('default', 'costpricepolicy', 'last-price');

$casos = [
'neto' => 90.0,
'precio' => 100.0,
'netomasextra' => 95.0,
'preciomasextra' => 105.0,
];

foreach ($casos as $calculo => $coste) {
Tools::settingsSet('default', 'calculocosteproveedor', $calculo);
CostPriceTools::update($variante);

$variante->load($variante->idvariante);
$this->assertEquals($coste, (float)$variante->coste, 'bad-calculo-' . $calculo);
}
}

public function testPrecioMedioConPrecioExtra(): void
{
$producto = $this->createProduct();
$variante = $producto->getVariants()[0];

$this->createSupplierProduct($producto, 100.0, '2024-01-01 00:00:00', 10.0, 5.0);
$this->createSupplierProduct($producto, 200.0, '2024-02-01 00:00:00', 20.0, 10.0);

Tools::settingsSet('default', 'costpricepolicy', 'average-price');
Tools::settingsSet('default', 'calculocosteproveedor', 'netomasextra');
CostPriceTools::update($variante);

$variante->load($variante->idvariante);
$this->assertEquals(132.5, (float)$variante->coste, 'bad-average-price-extra');
}

public function testUltimoPrecioConPrecioExtra(): void
{
$producto = $this->createProduct();
$variante = $producto->getVariants()[0];

$this->createSupplierProduct($producto, 100.0, '2024-01-01 00:00:00', 0.0, 5.0);
$this->createSupplierProduct($producto, 200.0, '2024-02-01 00:00:00', 0.0, 20.0);

Tools::settingsSet('default', 'costpricepolicy', 'last-price');
Tools::settingsSet('default', 'calculocosteproveedor', 'preciomasextra');
CostPriceTools::update($variante);

$variante->load($variante->idvariante);
$this->assertEquals(220.0, (float)$variante->coste, 'bad-last-price-extra');
}

private function createProduct(): Producto
{
$product = $this->getRandomProduct();
Expand All @@ -137,7 +193,8 @@ private function createSupplierProduct(
Producto $product,
float $precio,
string $actualizado,
float $dtopor = 0.0
float $dtopor = 0.0,
float $precioextra = 0.0
): ProductoProveedor {
// un proveedor distinto por fila para evitar el unique (codproveedor, refproveedor, referencia, coddivisa)
$supplier = $this->getRandomSupplier();
Expand All @@ -149,6 +206,7 @@ private function createSupplierProduct(
$row->idproducto = $product->idproducto;
$row->codproveedor = $supplier->codproveedor;
$row->precio = $precio;
$row->precioextra = $precioextra;
$row->dtopor = $dtopor;
$row->actualizado = $actualizado;
$this->assertTrue($row->save());
Expand Down
108 changes: 108 additions & 0 deletions Test/Core/Model/ProductoProveedorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use FacturaScripts\Core\Model\Proveedor;
use FacturaScripts\Core\Model\Variante;
use FacturaScripts\Core\Tools;
use FacturaScripts\Core\Where;
use FacturaScripts\Core\WorkQueue;
use FacturaScripts\Test\Traits\DefaultSettingsTrait;
use FacturaScripts\Test\Traits\LogErrorsTrait;
Expand Down Expand Up @@ -339,9 +340,116 @@ public function testClear(): void
$this->assertEquals(0, $productoProveedor->neto);
$this->assertEquals(0, $productoProveedor->netoeuros);
$this->assertEquals(0, $productoProveedor->precio);
$this->assertEquals(0, $productoProveedor->precioextra);
$this->assertEquals(0, $productoProveedor->stock);
}

public function testPrecioExtra(): void
{
$proveedor = $this->getRandomSupplier();
$this->assertTrue($proveedor->save());

$producto = $this->getRandomProduct();
$this->assertTrue($producto->save());

$productoProveedor = new ProductoProveedor();
$productoProveedor->codproveedor = $proveedor->codproveedor;
$productoProveedor->idproducto = $producto->idproducto;
$productoProveedor->precio = 100;
$productoProveedor->precioextra = 12.34;
$productoProveedor->referencia = $producto->referencia;
$this->assertTrue($productoProveedor->save());

$recargado = new ProductoProveedor();
$this->assertTrue($recargado->load($productoProveedor->id));
$this->assertEquals(12.34, (float)$recargado->precioextra);

$this->assertTrue($productoProveedor->delete());
$this->assertTrue($producto->delete());
$this->assertTrue($proveedor->getDefaultAddress()->delete());
$this->assertTrue($proveedor->delete());
}

public function testPrecioExtraActualizaCoste(): void
{
Tools::settingsSet('default', 'costpricepolicy', 'last-price');
Tools::settingsSet('default', 'calculocosteproveedor', 'netomasextra');

$proveedor = $this->getRandomSupplier();
$this->assertTrue($proveedor->save());

$producto = $this->getRandomProduct();
$this->assertTrue($producto->save());
$variante = $producto->getVariants()[0];

$productoProveedor = new ProductoProveedor();
$productoProveedor->codproveedor = $proveedor->codproveedor;
$productoProveedor->idproducto = $producto->idproducto;
$productoProveedor->precio = 100;
$productoProveedor->precioextra = 5;
$productoProveedor->referencia = $producto->referencia;
$this->assertTrue($productoProveedor->save());

$variante->reload();
$this->assertEquals(105.0, (float)$variante->coste);

$productoProveedor->precioextra = 15;
$this->assertTrue($productoProveedor->save());

$variante->reload();
$this->assertEquals(115.0, (float)$variante->coste);

$this->assertTrue($productoProveedor->delete());
$this->assertTrue($producto->delete());
$this->assertTrue($proveedor->getDefaultAddress()->delete());
$this->assertTrue($proveedor->delete());
}

public function testActualizarDesdeCompraMantienePrecioExtra(): void
{
Tools::settingsSet('default', 'updatesupplierprices', true);

[$proveedor, $producto, $albaran] = $this->getAlbaranConLineaProducto();

$productoProveedor = ProductoProveedor::all([
Where::eq('referencia', $producto->referencia),
Where::eq('codproveedor', $proveedor->codproveedor),
])[0];
$productoProveedor->actualizado = Tools::dateTime('- 1 day');
$productoProveedor->precioextra = 12.5;
$this->assertTrue($productoProveedor->save());

$albaran2 = new AlbaranProveedor();
$albaran2->setSubject($proveedor);
$this->assertTrue($albaran2->save());

$linea = $albaran2->getNewProductLine($producto->referencia);
$linea->pvpunitario = 25;
$linea->dtopor = 10;
$linea->dtopor2 = 0;
$this->assertTrue($linea->save());
$lineas = [$linea];
$this->assertTrue(Calculator::calculate($albaran2, $lineas, true));

while (true) {
if (false === WorkQueue::run()) {
break;
}
}

$productoProveedor->load($productoProveedor->id);
$this->assertEquals(12.5, (float)$productoProveedor->precioextra);
$this->assertEquals(25.0, (float)$productoProveedor->precio);
$this->assertEquals(22.5, (float)$productoProveedor->neto);

$this->assertTrue($albaran->delete());
$this->assertTrue($albaran2->delete());
$this->assertTrue($proveedor->getDefaultAddress()->delete());
$this->assertTrue($proveedor->delete());
$this->assertTrue($productoProveedor->delete());
$this->assertTrue($producto->delete());
}

public function testGetVariant(): void
{
$producto = $this->getRandomProduct();
Expand Down
Loading