@@ -12,12 +12,14 @@ use common\logic\Distribution\ProductDistribution\ProductDistributionBuilder; | |||
use common\logic\Distribution\ProductDistribution\ProductDistributionRepository; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\Order\Order\OrderRepository; | |||
use common\logic\Order\ProductOrder\ProductOrderBuilder; | |||
use common\logic\PointSale\PointSale\PointSale; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\Product\Product\Product; | |||
use common\logic\Product\Product\ProductRepository; | |||
use common\logic\Subscription\Subscription\Subscription; | |||
use common\logic\User\UserProducer\UserProducer; | |||
use common\logic\User\UserProducer\UserProducerRepository; | |||
class DistributionBuilder extends BaseService implements BuilderInterface | |||
{ | |||
@@ -29,6 +31,8 @@ class DistributionBuilder extends BaseService implements BuilderInterface | |||
protected ProductDistributionRepository $productDistributionRepository; | |||
protected ProductDistributionBuilder $productDistributionBuilder; | |||
protected OrderRepository $orderRepository; | |||
protected UserProducerRepository $userProducerRepository; | |||
protected ProductOrderBuilder $productOrderBuilder; | |||
public function __construct() | |||
{ | |||
@@ -39,6 +43,8 @@ class DistributionBuilder extends BaseService implements BuilderInterface | |||
$this->productRepository = $this->loadService(ProductRepository::class); | |||
$this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class); | |||
$this->orderRepository = $this->loadService(OrderRepository::class); | |||
$this->userProducerRepository = $this->loadService(UserProducerRepository::class); | |||
$this->productOrderBuilder = $this->loadService(ProductOrderBuilder::class); | |||
} | |||
public function instanciate(Producer $producer, string $date, bool $delivery = true): Distribution | |||
@@ -157,26 +163,21 @@ class DistributionBuilder extends BaseService implements BuilderInterface | |||
foreach ($ordersArray as $order) { | |||
foreach ($order->productOrder as $productOrder) { | |||
if ($productOrder->id_product == $product->id) { | |||
$productOrder->price = $product->price; | |||
$user = false; | |||
$userProducer = false; | |||
$user = null; | |||
$userProducer = null; | |||
if (isset($order->user) && $order->user) { | |||
$user = $order->user; | |||
$userProducer = UserProducer::searchOne([ | |||
'id_user' => $user->id, | |||
'id_producer' => $order->distribution->id_producer | |||
]); | |||
$userProducer = $this->userProducerRepository->getOne($user, $distribution->producer); | |||
} | |||
$productOrder->price = $product->getPrice([ | |||
'user' => $user, | |||
'user_producer' => $userProducer, | |||
'point_sale' => $order->pointSale, | |||
'quantity' => $productOrder->quantity | |||
]); | |||
$productOrder->save(); | |||
$this->productOrderBuilder->updatePrice( | |||
$productOrder, | |||
$user, | |||
$userProducer, | |||
$order->pointSale, | |||
$productOrder->quantity | |||
); | |||
} | |||
} | |||
} |
@@ -19,6 +19,13 @@ class DistributionRepository extends BaseService implements RepositoryInterface | |||
]; | |||
} | |||
public function getOneById($id): ?Distribution | |||
{ | |||
return Distribution::searchOne([ | |||
'id' => $id | |||
]); | |||
} | |||
public function getOne(Producer $producer, string $date) | |||
{ | |||
$paramsDistribution = [ |
@@ -6,15 +6,21 @@ use common\helpers\GlobalParam; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Distribution\Distribution\Distribution; | |||
use common\logic\Distribution\Distribution\DistributionRepository; | |||
use common\logic\PointSale\PointSale\PointSale; | |||
use common\logic\PointSale\PointSale\PointSaleRepository; | |||
class PointSaleDistributionBuilder extends BaseService implements BuilderInterface | |||
{ | |||
protected PointSaleDistributionRepository $pointSaleDistributionRepository; | |||
protected PointSaleRepository $pointSaleRepository; | |||
protected DistributionRepository $distributionRepository; | |||
public function __construct() | |||
{ | |||
$this->pointSaleDistributionRepository = $this->loadService(PointSaleDistributionRepository::class); | |||
$this->pointSaleRepository = $this->loadService(PointSaleRepository::class); | |||
$this->distributionRepository = $this->loadService(DistributionRepository::class); | |||
} | |||
/** | |||
@@ -45,7 +51,7 @@ class PointSaleDistributionBuilder extends BaseService implements BuilderInterfa | |||
{ | |||
$pointSaleDistribution = $this->pointSaleDistributionRepository->getOne($distribution, $pointSale); | |||
if(!$pointSaleDistribution) { | |||
if (!$pointSaleDistribution) { | |||
$pointSaleDistribution = $this->create($distribution, $pointSale); | |||
} | |||
@@ -58,30 +64,16 @@ class PointSaleDistributionBuilder extends BaseService implements BuilderInterfa | |||
// setAll | |||
public function createAll(Distribution $distribution, bool $delivery): void | |||
{ | |||
$arrPointsSale = PointSale::find() | |||
->with(['pointSaleDistribution' => function($q) use ($distribution) { | |||
$q->where(['id_distribution' => $distribution->id]); | |||
}]) | |||
->where([ | |||
'id_producer' => GlobalParam::getCurrentProducerId(), | |||
]) | |||
->all(); | |||
foreach ($arrPointsSale as $pointSale) { | |||
if(!$pointSale->pointSaleDistribution) { | |||
$pointSaleArray = $this->pointSaleRepository->getByDistribution($distribution); | |||
foreach ($pointSaleArray as $pointSale) { | |||
if (!$pointSale->pointSaleDistribution) { | |||
$this->create($distribution, $pointSale); | |||
} | |||
} | |||
$distribution = Distribution::findOne($distribution->id); | |||
if ($distribution) { | |||
$arrPointsSaleDistribution = PointSaleDistribution::searchAll([ | |||
'id_distribution' => $distribution->id | |||
]) ; | |||
foreach ($arrPointsSaleDistribution as $pointSaleDistribution) { | |||
$this->initDelivery($pointSaleDistribution, $delivery); | |||
} | |||
$pointSaleDistributionArray = $this->pointSaleDistributionRepository->getByDistribution($distribution); | |||
foreach ($pointSaleDistributionArray as $pointSaleDistribution) { | |||
$this->initDelivery($pointSaleDistribution, $delivery); | |||
} | |||
} | |||
@@ -26,6 +26,13 @@ class PointSaleDistributionRepository extends BaseService implements RepositoryI | |||
]); | |||
} | |||
public function getByDistribution(Distribution $distribution) | |||
{ | |||
return PointSaleDistribution::searchAll([ | |||
'id_distribution' => $distribution->id | |||
]) ; | |||
} | |||
public function countByDistribution(Distribution $distribution): int | |||
{ | |||
return PointSaleDistribution::searchCount([ |
@@ -1,40 +1,40 @@ | |||
<?php | |||
/** | |||
Copyright distrib (2018) | |||
contact@opendistrib.net | |||
Ce logiciel est un programme informatique servant à aider les producteurs | |||
à distribuer leur production en circuits courts. | |||
Ce logiciel est régi par la licence CeCILL soumise au droit français et | |||
respectant les principes de diffusion des logiciels libres. Vous pouvez | |||
utiliser, modifier et/ou redistribuer ce programme sous les conditions | |||
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA | |||
sur le site "http://www.cecill.info". | |||
En contrepartie de l'accessibilité au code source et des droits de copie, | |||
de modification et de redistribution accordés par cette licence, il n'est | |||
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, | |||
seule une responsabilité restreinte pèse sur l'auteur du programme, le | |||
titulaire des droits patrimoniaux et les concédants successifs. | |||
A cet égard l'attention de l'utilisateur est attirée sur les risques | |||
associés au chargement, à l'utilisation, à la modification et/ou au | |||
développement et à la reproduction du logiciel par l'utilisateur étant | |||
donné sa spécificité de logiciel libre, qui peut le rendre complexe à | |||
manipuler et qui le réserve donc à des développeurs et des professionnels | |||
avertis possédant des connaissances informatiques approfondies. Les | |||
utilisateurs sont donc invités à charger et tester l'adéquation du | |||
logiciel à leurs besoins dans des conditions permettant d'assurer la | |||
sécurité de leurs systèmes et ou de leurs données et, plus généralement, | |||
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. | |||
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez | |||
pris connaissance de la licence CeCILL, et que vous en avez accepté les | |||
termes. | |||
*/ | |||
/** | |||
* Copyright distrib (2018) | |||
* | |||
* contact@opendistrib.net | |||
* | |||
* Ce logiciel est un programme informatique servant à aider les producteurs | |||
* à distribuer leur production en circuits courts. | |||
* | |||
* Ce logiciel est régi par la licence CeCILL soumise au droit français et | |||
* respectant les principes de diffusion des logiciels libres. Vous pouvez | |||
* utiliser, modifier et/ou redistribuer ce programme sous les conditions | |||
* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA | |||
* sur le site "http://www.cecill.info". | |||
* | |||
* En contrepartie de l'accessibilité au code source et des droits de copie, | |||
* de modification et de redistribution accordés par cette licence, il n'est | |||
* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, | |||
* seule une responsabilité restreinte pèse sur l'auteur du programme, le | |||
* titulaire des droits patrimoniaux et les concédants successifs. | |||
* | |||
* A cet égard l'attention de l'utilisateur est attirée sur les risques | |||
* associés au chargement, à l'utilisation, à la modification et/ou au | |||
* développement et à la reproduction du logiciel par l'utilisateur étant | |||
* donné sa spécificité de logiciel libre, qui peut le rendre complexe à | |||
* manipuler et qui le réserve donc à des développeurs et des professionnels | |||
* avertis possédant des connaissances informatiques approfondies. Les | |||
* utilisateurs sont donc invités à charger et tester l'adéquation du | |||
* logiciel à leurs besoins dans des conditions permettant d'assurer la | |||
* sécurité de leurs systèmes et ou de leurs données et, plus généralement, | |||
* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. | |||
* | |||
* Le fait que vous puissiez accéder à cet en-tête signifie que vous avez | |||
* pris connaissance de la licence CeCILL, et que vous en avez accepté les | |||
* termes. | |||
*/ | |||
namespace common\logic\Document\DeliveryNote; | |||
@@ -42,52 +42,20 @@ use common\logic\Document\Document\Document; | |||
class DeliveryNote extends Document | |||
{ | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'delivery_note'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->relationOrders('id_delivery_note') ; | |||
} | |||
public function getInvoiceId() | |||
{ | |||
if($this->orders && count($this->orders) > 0) { | |||
foreach($this->orders as $order) { | |||
if($order->id_invoice) { | |||
return $order->id_invoice; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
public function isInvoiced() | |||
{ | |||
return (bool) $this->getInvoiceId(); | |||
} | |||
public function getInvoice() | |||
{ | |||
$invoice = null; | |||
$idInvoice = $this->getInvoiceId(); | |||
if($idInvoice) { | |||
$invoice = Invoice::searchOne([ | |||
'id' => $idInvoice | |||
]); | |||
} | |||
return $invoice; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'delivery_note'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->relationOrders('id_delivery_note'); | |||
} | |||
} |
@@ -14,14 +14,14 @@ class DeliveryNoteContainer implements ContainerInterface | |||
public function getServices(): array | |||
{ | |||
return [ | |||
DeliveryNoteFactory::class, | |||
DeliveryNoteBuilder::class, | |||
DeliveryNoteSolver::class, | |||
]; | |||
} | |||
public function getFactory(): DeliveryNoteFactory | |||
public function getFactory(): DeliveryNoteBuilder | |||
{ | |||
return new DeliveryNoteFactory(); | |||
return new DeliveryNoteBuilder(); | |||
} | |||
public function getSolver(): DeliveryNoteSolver |
@@ -39,59 +39,61 @@ | |||
namespace common\logic\Document\DeliveryNote; | |||
use common\helpers\GlobalParam; | |||
use common\logic\PointSale\PointSale\DeliveryNoteRepository; | |||
use yii\data\ActiveDataProvider; | |||
class DeliveryNoteSearch extends DeliveryNote | |||
{ | |||
public $id_point_sale ; | |||
public $date_distribution ; | |||
public $id_point_sale; | |||
public $date_distribution; | |||
public function rules() | |||
{ | |||
return [ | |||
[[], 'safe'], | |||
[['comment', 'address', 'status', 'date_distribution'], 'string'], | |||
[['id_user', 'id_point_sale'], 'integer'], | |||
[['name', 'reference'], 'string', 'max' => 255], | |||
]; | |||
} | |||
public function search($params) | |||
{ | |||
$optionsSearch = self::defaultOptionsSearch(); | |||
public function rules() | |||
{ | |||
return [ | |||
[[], 'safe'], | |||
[['comment', 'address', 'status', 'date_distribution'], 'string'], | |||
[['id_user', 'id_point_sale'], 'integer'], | |||
[['name', 'reference'], 'string', 'max' => 255], | |||
]; | |||
} | |||
$query = DeliveryNote::find() | |||
->with($optionsSearch['with']) | |||
->joinWith($optionsSearch['join_with']) | |||
->where(['delivery_note.id_producer' => GlobalParam::getCurrentProducerId()]) | |||
->orderBy('delivery_note.status ASC, delivery_note.reference DESC') | |||
->groupBy('delivery_note.id'); | |||
public function search($params) | |||
{ | |||
$deliveryNoteRepository = new DeliveryNoteRepository(); | |||
$optionsSearch = $deliveryNoteRepository->defaultOptionsSearch(); | |||
$dataProvider = new ActiveDataProvider([ | |||
'query' => $query, | |||
'sort' => ['attributes' => ['name', 'reference', 'date']], | |||
'pagination' => [ | |||
'pageSize' => 20, | |||
], | |||
]); | |||
$query = DeliveryNote::find() | |||
->with($optionsSearch['with']) | |||
->joinWith($optionsSearch['join_with']) | |||
->where(['delivery_note.id_producer' => GlobalParam::getCurrentProducerId()]) | |||
->orderBy('delivery_note.status ASC, delivery_note.reference DESC') | |||
->groupBy('delivery_note.id'); | |||
$this->load($params); | |||
if (!$this->validate()) { | |||
return $dataProvider; | |||
} | |||
$dataProvider = new ActiveDataProvider([ | |||
'query' => $query, | |||
'sort' => ['attributes' => ['name', 'reference', 'date']], | |||
'pagination' => [ | |||
'pageSize' => 20, | |||
], | |||
]); | |||
$query->andFilterWhere(['like', 'delivery_note.name', $this->name]); | |||
$query->andFilterWhere(['like', 'delivery_note.reference', $this->reference]); | |||
$query->andFilterWhere(['like', 'delivery_note.status', $this->status]); | |||
$this->load($params); | |||
if (!$this->validate()) { | |||
return $dataProvider; | |||
} | |||
if($this->id_point_sale) { | |||
$query->andWhere(['order.id_point_sale' => $this->id_point_sale]); | |||
} | |||
$query->andFilterWhere(['like', 'delivery_note.name', $this->name]); | |||
$query->andFilterWhere(['like', 'delivery_note.reference', $this->reference]); | |||
$query->andFilterWhere(['like', 'delivery_note.status', $this->status]); | |||
if($this->date_distribution && strlen($this->date_distribution)) { | |||
$query->andFilterWhere(['like', 'distribution.date', date('Y-m-d',strtotime(str_replace('/','-',$this->date_distribution)))]); | |||
} | |||
if ($this->id_point_sale) { | |||
$query->andWhere(['order.id_point_sale' => $this->id_point_sale]); | |||
} | |||
return $dataProvider; | |||
if ($this->date_distribution && strlen($this->date_distribution)) { | |||
$query->andFilterWhere(['like', 'distribution.date', date('Y-m-d', strtotime(str_replace('/', '-', $this->date_distribution)))]); | |||
} | |||
return $dataProvider; | |||
} | |||
} |
@@ -3,9 +3,34 @@ | |||
namespace common\logic\Document\DeliveryNote; | |||
use common\logic\BaseService; | |||
use common\logic\Document\Invoice\Invoice; | |||
use common\logic\SolverInterface; | |||
class DeliveryNoteSolver extends BaseService implements SolverInterface | |||
{ | |||
public function getInvoiceId(DeliveryNote $deliveryNote): ?int | |||
{ | |||
if($deliveryNote->orders && count($deliveryNote->orders) > 0) { | |||
foreach($deliveryNote->orders as $order) { | |||
if($order->id_invoice) { | |||
return $order->id_invoice; | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
public function isInvoiced(DeliveryNote $deliveryNote): bool | |||
{ | |||
return (bool) $this->getInvoiceId($deliveryNote); | |||
} | |||
public function getInvoice(DeliveryNote $deliveryNote): ?Invoice | |||
{ | |||
$idInvoice = (int) $this->getInvoiceId($deliveryNote); | |||
return Invoice::searchOne([ | |||
'id' => $idInvoice | |||
]); | |||
} | |||
} |
@@ -40,11 +40,14 @@ namespace common\logic\Document\Document; | |||
use common\components\ActiveRecordCommon; | |||
use common\helpers\GlobalParam; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\Order\Order\OrderRepository; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\User\User\User; | |||
use kartik\mpdf\Pdf; | |||
use yii\base\ErrorException; | |||
class Document extends ActiveRecordCommon | |||
class Document extends ActiveRecordCommon implements DocumentInterface | |||
{ | |||
const STATUS_DRAFT = 'draft'; | |||
const STATUS_VALID = 'valid'; | |||
@@ -100,7 +103,7 @@ class Document extends ActiveRecordCommon | |||
public function getUser() | |||
{ | |||
return $this->hasOne( User::className(), ['id' => 'id_user']); | |||
return $this->hasOne(User::class, ['id' => 'id_user']); | |||
} | |||
public function getProducer() | |||
@@ -110,9 +113,10 @@ class Document extends ActiveRecordCommon | |||
public function relationOrders($fieldIdDocument) | |||
{ | |||
$defaultOptionsSearch = Order::defaultOptionsSearch(); | |||
$orderRepository = new OrderRepository(); | |||
$defaultOptionsSearch = $orderRepository->defaultOptionsSearch(); | |||
return $this->hasMany(Order::className(), [$fieldIdDocument => 'id']) | |||
return $this->hasMany(Order::class, [$fieldIdDocument => 'id']) | |||
->with($defaultOptionsSearch['with']) | |||
->joinWith($defaultOptionsSearch['join_with']) | |||
->orderBy('distribution.date ASC'); | |||
@@ -122,136 +126,7 @@ class Document extends ActiveRecordCommon | |||
* Méthodes | |||
*/ | |||
public function getAmount($type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($type, false, $format); | |||
} | |||
public function getAmountWithTax($type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($type, true, $format); | |||
} | |||
protected function _getAmountGeneric($type = Order::AMOUNT_TOTAL, $withTax = true, $format = false) | |||
{ | |||
$amount = 0; | |||
$totalVat = 0; | |||
$ordersArray = $this->orders; | |||
// Méthode de calcul via les commandes liées | |||
/*foreach ($ordersArray as $order) { | |||
$order->init($this->tax_calculation_method); | |||
$amount += $order->getAmount($type); | |||
$totalVat += $order->getTotalVat($type); | |||
}*/ | |||
// Méthode de calcul via getProductOrders() | |||
foreach($this->getProductsOrders() as $productOrderArray) { | |||
foreach($productOrderArray as $productOrder) { | |||
$priceLine = $productOrder->getPriceByTypeTotal($type) * $productOrder->quantity; | |||
$amount += $priceLine; | |||
$totalVat += Price::getVat($priceLine, $productOrder->taxRate->value, $this->tax_calculation_method); | |||
} | |||
} | |||
if ($this->isTaxCalculationMethodRoundingOfTheSum()) { | |||
$totalVat = Price::round($totalVat); | |||
} | |||
if ($withTax) { | |||
$amount += $totalVat; | |||
} | |||
if ($format) { | |||
return Price::format($amount); | |||
} else { | |||
return $amount; | |||
} | |||
} | |||
public function getTotalVatArray($typeTotal) | |||
{ | |||
$totalVatArray = []; | |||
// Méthode de calcul via les commandes liées | |||
/*$ordersArray = $this->orders; | |||
foreach ($ordersArray as $order) { | |||
$order->init($this->tax_calculation_method); | |||
$fieldNameVat = $order->getFieldNameAmount($typeTotal, 'vat'); | |||
foreach ($order->$fieldNameVat as $idTaxRate => $vat) { | |||
if (!isset($totalVatArray[$idTaxRate])) { | |||
$totalVatArray[$idTaxRate] = 0; | |||
} | |||
$totalVatArray[$idTaxRate] += $vat; | |||
} | |||
}*/ | |||
// Méthode de calcul via getProductOrders() | |||
foreach($this->getProductsOrders() as $productOrderArray) { | |||
foreach ($productOrderArray as $productOrder) { | |||
$idTaxRate = $productOrder->taxRate->id; | |||
if (!isset($totalVatArray[$idTaxRate])) { | |||
$totalVatArray[$idTaxRate] = 0; | |||
} | |||
$totalVatArray[$idTaxRate] += Price::getVat( | |||
$productOrder->getPriceByTypeTotal($typeTotal) * $productOrder->quantity, | |||
$productOrder->taxRate->value, | |||
$this->tax_calculation_method | |||
); | |||
} | |||
} | |||
return $totalVatArray; | |||
} | |||
public function getPointSale() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->pointSale; | |||
} else { | |||
return ''; | |||
} | |||
} | |||
public function getDistribution() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->distribution; | |||
} else { | |||
return ''; | |||
} | |||
} | |||
public function getClass() | |||
{ | |||
return str_replace('common\models\\', '', get_class($this)); | |||
} | |||
public function getType() | |||
{ | |||
$class = $this->getClass(); | |||
if ($class == 'Invoice') { | |||
$documentType = 'Facture'; | |||
} elseif ($class == 'DeliveryNote') { | |||
$documentType = 'Bon de livraison'; | |||
} elseif ($class == 'Quotation') { | |||
$documentType = 'Devis'; | |||
} | |||
if (isset($documentType)) { | |||
return $documentType; | |||
} | |||
return ''; | |||
} | |||
public function isValidClass($typeDocument) | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); | |||
} | |||
public function generateReference() | |||
{ |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace common\logic\Document\Document; | |||
interface DocumentInterface | |||
{ | |||
} |
@@ -3,9 +3,117 @@ | |||
namespace common\logic\Document\Document; | |||
use common\logic\BaseService; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\SolverInterface; | |||
class DocumentSolver extends BaseService implements SolverInterface | |||
{ | |||
public function getAmount(DocumentInterface $document, $type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($document, $type, false, $format); | |||
} | |||
public function getAmountWithTax(DocumentInterface $document, $type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($document, $type, true, $format); | |||
} | |||
protected function _getAmountGeneric(DocumentInterface $document, $type = Order::AMOUNT_TOTAL, $withTax = true, $format = false) | |||
{ | |||
$amount = 0; | |||
$totalVat = 0; | |||
foreach($document->getProductsOrders() as $productOrderArray) { | |||
foreach($productOrderArray as $productOrder) { | |||
$priceLine = $productOrder->getPriceByTypeTotal($type) * $productOrder->quantity; | |||
$amount += $priceLine; | |||
$totalVat += Price::getVat($priceLine, $productOrder->taxRate->value, $document->tax_calculation_method); | |||
} | |||
} | |||
if ($this->isTaxCalculationMethodRoundingOfTheSum()) { | |||
$totalVat = Price::round($totalVat); | |||
} | |||
if ($withTax) { | |||
$amount += $totalVat; | |||
} | |||
if ($format) { | |||
return Price::format($amount); | |||
} else { | |||
return $amount; | |||
} | |||
} | |||
public function getTotalVatArray($typeTotal) | |||
{ | |||
$totalVatArray = []; | |||
// Méthode de calcul via getProductOrders() | |||
foreach($this->getProductsOrders() as $productOrderArray) { | |||
foreach ($productOrderArray as $productOrder) { | |||
$idTaxRate = $productOrder->taxRate->id; | |||
if (!isset($totalVatArray[$idTaxRate])) { | |||
$totalVatArray[$idTaxRate] = 0; | |||
} | |||
$totalVatArray[$idTaxRate] += Price::getVat( | |||
$productOrder->getPriceByTypeTotal($typeTotal) * $productOrder->quantity, | |||
$productOrder->taxRate->value, | |||
$this->tax_calculation_method | |||
); | |||
} | |||
} | |||
return $totalVatArray; | |||
} | |||
public function getPointSale() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->pointSale; | |||
} else { | |||
return ''; | |||
} | |||
} | |||
public function getDistribution() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->distribution; | |||
} else { | |||
return ''; | |||
} | |||
} | |||
public function getClass() | |||
{ | |||
return str_replace('common\models\\', '', get_class($this)); | |||
} | |||
public function getType() | |||
{ | |||
$class = $this->getClass(); | |||
if ($class == 'Invoice') { | |||
$documentType = 'Facture'; | |||
} elseif ($class == 'DeliveryNote') { | |||
$documentType = 'Bon de livraison'; | |||
} elseif ($class == 'Quotation') { | |||
$documentType = 'Devis'; | |||
} | |||
if (isset($documentType)) { | |||
return $documentType; | |||
} | |||
return ''; | |||
} | |||
public function isValidClass($typeDocument) | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); | |||
} | |||
} |
@@ -198,27 +198,6 @@ class Order extends ActiveRecordCommon | |||
return $this->hasOne(DeliveryNote::className(), ['id' => 'id_delivery_note']); | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => [ | |||
'productOrder', | |||
'productOrder.product', | |||
'creditHistory', | |||
'creditHistory.userAction', | |||
'pointSale' | |||
], | |||
'join_with' => ['distribution', 'user', 'user.userProducer'], | |||
'orderby' => 'order.date ASC', | |||
'attribute_id_producer' => 'distribution.id_producer' | |||
]; | |||
} | |||
/** | |||
* Initialise le montant total, le montant déjà payé et le poids de la | |||
* commande. |
@@ -8,6 +8,22 @@ use common\logic\RepositoryInterface; | |||
class OrderRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => [ | |||
'productOrder', | |||
'productOrder.product', | |||
'creditHistory', | |||
'creditHistory.userAction', | |||
'pointSale' | |||
], | |||
'join_with' => ['distribution', 'user', 'user.userProducer'], | |||
'orderby' => 'order.date ASC', | |||
'attribute_id_producer' => 'distribution.id_producer' | |||
]; | |||
} | |||
public function getByDistribution(Distribution $distribution, string $conditionAppend = '') | |||
{ | |||
return Order::searchAll([ |
@@ -4,13 +4,45 @@ namespace common\logic\Order\ProductOrder; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\PointSale\PointSale\PointSale; | |||
use common\logic\Product\Product\ProductSolver; | |||
use common\logic\User\User\User; | |||
use common\logic\User\UserProducer\UserProducer; | |||
class ProductOrderBuilder extends BaseService implements BuilderInterface | |||
{ | |||
protected ProductSolver $productSolver; | |||
public function __construct() | |||
{ | |||
$this->productSolver = $this->loadService(ProductSolver::class); | |||
} | |||
public function instanciate(): ProductOrder | |||
{ | |||
$productOrder = new ProductOrder(); | |||
return $productOrder; | |||
} | |||
public function updatePrice( | |||
ProductOrder $productOrder, | |||
User $user = null, | |||
UserProducer $userProducer = null, | |||
PointSale $pointSale = null, | |||
int $quantity = 1) | |||
{ | |||
$productOrder->price = $this->productSolver->getPrice( | |||
$productOrder->product, | |||
[ | |||
'user' => $user, | |||
'user_producer' => $userProducer, | |||
'point_sale' => $pointSale, | |||
'quantity' => $quantity | |||
]); | |||
$productOrder->save(); | |||
return $productOrder; | |||
} | |||
} |
@@ -2,11 +2,23 @@ | |||
namespace common\logic\PointSale\PointSale; | |||
use common\helpers\GlobalParam; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Distribution\Distribution\Distribution; | |||
use common\logic\RepositoryInterface; | |||
class PointSaleRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function getByDistribution(Distribution $distribution) | |||
{ | |||
return PointSale::find() | |||
->with(['pointSaleDistribution' => function($q) use ($distribution) { | |||
$q->where(['id_distribution' => $distribution->id]); | |||
}]) | |||
->where([ | |||
'id_producer' => $distribution->producer->id, | |||
]) | |||
->all(); | |||
} | |||
} |
@@ -448,58 +448,6 @@ class Product extends ActiveRecordCommon | |||
return false; | |||
} | |||
public function getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale) | |||
{ | |||
$priorityMatchSpecificPrice = ProductPrice::getPriorityMatchOfSpecificPriceArray($specificPrices, $user, $pointSale); | |||
$specificPricesFilter = []; | |||
foreach ($specificPrices as $keySpecificPrice => $specificPrice) { | |||
if (($priorityMatchSpecificPrice && $specificPrice->$priorityMatchSpecificPrice($user, $pointSale)) | |||
|| $specificPrice->matchFromQuantityOnly()) { | |||
$specificPricesFilter[] = $specificPrice; | |||
} | |||
} | |||
return $specificPricesFilter; | |||
} | |||
public function getPrice($params = []) | |||
{ | |||
$specificPrices = $this->productPrice; | |||
$user = isset($params['user']) ? $params['user'] : false; | |||
$userProducer = isset($params['user_producer']) ? $params['user_producer'] : false; | |||
$pointSale = isset($params['point_sale']) ? $params['point_sale'] : false; | |||
$quantity = (isset($params['quantity']) && $params['quantity']) ? $params['quantity'] : 1; | |||
if ($specificPrices && ($user || $pointSale)) { | |||
$specificPrices = $this->getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale); | |||
$bestPrice = 9999; | |||
foreach ($specificPrices as $specificPrice) { | |||
$fromQuantity = $specificPrice->from_quantity; | |||
if ((($fromQuantity && $fromQuantity <= $quantity) || !$fromQuantity) | |||
&& $specificPrice->price < $bestPrice) { | |||
$bestPrice = $specificPrice->price; | |||
} | |||
} | |||
if ($bestPrice != 9999) { | |||
return $bestPrice; | |||
} | |||
} | |||
if ($userProducer && $userProducer->product_price_percent) { | |||
return $this->price * (1 + $userProducer->product_price_percent / 100); | |||
} | |||
if ($pointSale && $pointSale->product_price_percent) { | |||
return $this->price * (1 + $pointSale->product_price_percent / 100); | |||
} | |||
return $this->price; | |||
} | |||
/** | |||
* Retourne le prix du produit avec taxe | |||
*/ |
@@ -3,9 +3,57 @@ | |||
namespace common\logic\Product\Product; | |||
use common\logic\BaseService; | |||
use common\logic\PointSale\PointSale\PointSale; | |||
use common\logic\Product\ProductPrice\ProductPriceSolver; | |||
use common\logic\SolverInterface; | |||
use common\logic\User\User\User; | |||
class ProductSolver extends BaseService implements SolverInterface | |||
{ | |||
protected ProductPriceSolver $productPriceSolver; | |||
public function __construct() | |||
{ | |||
$this->productPriceSolver = $this->loadService(ProductPriceSolver::class); | |||
} | |||
public function getPrice(Product $product, array $params = []): float | |||
{ | |||
$specificPriceArray = $product->productPrice; | |||
$user = isset($params['user']) ? $params['user'] : false; | |||
$userProducer = isset($params['user_producer']) ? $params['user_producer'] : false; | |||
$pointSale = isset($params['point_sale']) ? $params['point_sale'] : false; | |||
$quantity = (isset($params['quantity']) && $params['quantity']) ? $params['quantity'] : 1; | |||
if ($specificPriceArray && ($user || $pointSale)) { | |||
$specificPriceArray = $this->productPriceSolver->filterByPriorityMatch( | |||
$specificPriceArray, | |||
$user, | |||
$pointSale | |||
); | |||
$bestPrice = 9999; | |||
foreach ($specificPriceArray as $specificPrice) { | |||
$fromQuantity = $specificPrice->from_quantity; | |||
if ((($fromQuantity && $fromQuantity <= $quantity) || !$fromQuantity) | |||
&& $specificPrice->price < $bestPrice) { | |||
$bestPrice = $specificPrice->price; | |||
} | |||
} | |||
if ($bestPrice != 9999) { | |||
return $bestPrice; | |||
} | |||
} | |||
if ($userProducer && $userProducer->product_price_percent) { | |||
return $product->price * (1 + $userProducer->product_price_percent / 100); | |||
} | |||
if ($pointSale && $pointSale->product_price_percent) { | |||
return $product->price * (1 + $pointSale->product_price_percent / 100); | |||
} | |||
return $product->price; | |||
} | |||
} |
@@ -180,95 +180,4 @@ class ProductPrice extends ActiveRecordCommon | |||
return $percentValues; | |||
} | |||
public static function hasMatchOfType($specificPriceArray, $typeMatch, $user, $pointSale) | |||
{ | |||
foreach($specificPriceArray as $specificPrice) { | |||
if($specificPrice->$typeMatch($user, $pointSale)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
public static function getPriorityMatchOfSpecificPriceArray($specificPriceArray, $user, $pointSale) | |||
{ | |||
if(self::hasMatchOfType($specificPriceArray, 'matchUser', $user, $pointSale)) { | |||
return 'matchUser'; | |||
} | |||
if(self::hasMatchOfType($specificPriceArray, 'matchUserGroup', $user, $pointSale)) { | |||
return 'matchUserGroup'; | |||
} | |||
if(self::hasMatchOfType($specificPriceArray, 'matchPointSale', $user, $pointSale)) { | |||
return 'matchPointSale'; | |||
} | |||
if(self::hasMatchOfType($specificPriceArray, 'matchUserPointSale', $user, $pointSale)) { | |||
return 'matchUserPointSale'; | |||
} | |||
if(self::hasMatchOfType($specificPriceArray, 'matchUserGroupPointSale', $user, $pointSale)) { | |||
return 'matchUserGroupPointSale'; | |||
} | |||
return null; | |||
} | |||
public function matchUser($user, $pointSale) | |||
{ | |||
return $user | |||
&& $this->id_user | |||
&& !$this->id_point_sale | |||
&& !$this->id_user_group | |||
&& $this->id_user == $user->id; | |||
} | |||
public function matchUserGroup($user, $pointSale) | |||
{ | |||
return $user | |||
&& $this->id_user_group | |||
&& !$this->id_point_sale | |||
&& !$this->id_user | |||
&& $user->belongsToUserGroup($this->id_user_group); | |||
} | |||
public function matchPointSale($user, $pointSale) | |||
{ | |||
return $pointSale | |||
&& $this->id_point_sale | |||
&& !$this->id_user | |||
&& !$this->id_user_group | |||
&& $this->id_point_sale == $pointSale->id; | |||
} | |||
public function matchUserPointSale($user, $pointSale) | |||
{ | |||
return $pointSale && $user | |||
&& $this->id_point_sale | |||
&& $this->id_user | |||
&& $this->id_point_sale == $pointSale->id | |||
&& $this->id_user == $user->id; | |||
} | |||
public function matchUserGroupPointSale($user, $pointSale) | |||
{ | |||
return $user | |||
&& $pointSale | |||
&& $this->id_user_group | |||
&& $this->id_point_sale | |||
&& !$this->id_user | |||
&& $user->belongsToUserGroup($this->id_user_group) | |||
&& $this->id_point_sale == $pointSale->id; | |||
} | |||
public function matchFromQuantityOnly() | |||
{ | |||
return !$this->id_user | |||
&& !$this->id_point_sale | |||
&& !$this->id_user_group | |||
&& $this->from_quantity; | |||
} | |||
} |
@@ -3,9 +3,122 @@ | |||
namespace common\logic\Product\ProductPrice; | |||
use common\logic\BaseService; | |||
use common\logic\PointSale\PointSale\PointSale; | |||
use common\logic\SolverInterface; | |||
use common\logic\User\User\User; | |||
class ProductPriceSolver extends BaseService implements SolverInterface | |||
{ | |||
// getSpecificPricesFilterByPriorityMatch | |||
public function filterByPriorityMatch( | |||
array $specificPrices, | |||
User $user, | |||
PointSale $pointSale): array | |||
{ | |||
$priorityMatchSpecificPrice = $this->getPriorityMatch($specificPrices, $user, $pointSale); | |||
$specificPricesFilter = []; | |||
foreach ($specificPrices as $keySpecificPrice => $specificPrice) { | |||
if (($priorityMatchSpecificPrice && $specificPrice->$priorityMatchSpecificPrice($user, $pointSale)) | |||
|| $specificPrice->matchFromQuantityOnly()) { | |||
$specificPricesFilter[] = $specificPrice; | |||
} | |||
} | |||
return $specificPricesFilter; | |||
} | |||
// getPriorityMatchOfSpecificPriceArray | |||
public function getPriorityMatch( | |||
array $specificPriceArray, | |||
User $user = null, | |||
PointSale $pointSale = null): ?string | |||
{ | |||
$typeMatchArray = [ | |||
'matchUser', | |||
'matchUserGroup', | |||
'matchPointSale', | |||
'matchUserPointSale', | |||
'matchUserGroupPointSale' | |||
]; | |||
foreach($typeMatchArray as $typeMatch) { | |||
if($this->hasMatchOfType($specificPriceArray, $typeMatch, $user, $pointSale)) { | |||
return $typeMatch; | |||
} | |||
} | |||
return null; | |||
} | |||
public function hasMatchOfType( | |||
array $specificPriceArray, | |||
string $typeMatch, | |||
User $user = null, | |||
PointSale $pointSale = null): bool | |||
{ | |||
foreach($specificPriceArray as $specificPrice) { | |||
if($specificPrice->$typeMatch($user, $pointSale)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
public function matchUser(ProductPrice $productPrice, User $user = null, PointSale $pointSale = null): bool | |||
{ | |||
return $user | |||
&& $productPrice->id_user | |||
&& !$productPrice->id_point_sale | |||
&& !$productPrice->id_user_group | |||
&& $productPrice->id_user == $user->id; | |||
} | |||
public function matchUserGroup(ProductPrice $productPrice, User $user = null, PointSale $pointSale = null): bool | |||
{ | |||
return $user | |||
&& $productPrice->id_user_group | |||
&& !$productPrice->id_point_sale | |||
&& !$productPrice->id_user | |||
&& $user->belongsToUserGroup($productPrice->id_user_group); | |||
} | |||
public function matchPointSale(ProductPrice $productPrice, User $user = null, PointSale $pointSale = null): bool | |||
{ | |||
return $pointSale | |||
&& $productPrice->id_point_sale | |||
&& !$productPrice->id_user | |||
&& !$productPrice->id_user_group | |||
&& $productPrice->id_point_sale == $pointSale->id; | |||
} | |||
public function matchUserPointSale(ProductPrice $productPrice, User $user = null, PointSale $pointSale = null): bool | |||
{ | |||
return $pointSale && $user | |||
&& $productPrice->id_point_sale | |||
&& $productPrice->id_user | |||
&& $productPrice->id_point_sale == $pointSale->id | |||
&& $productPrice->id_user == $user->id; | |||
} | |||
public function matchUserGroupPointSale(ProductPrice $productPrice, User $user = null, PointSale $pointSale = null): bool | |||
{ | |||
return $user | |||
&& $pointSale | |||
&& $productPrice->id_user_group | |||
&& $productPrice->id_point_sale | |||
&& !$productPrice->id_user | |||
&& $user->belongsToUserGroup($productPrice->id_user_group) | |||
&& $productPrice->id_point_sale == $pointSale->id; | |||
} | |||
public function matchFromQuantityOnly(ProductPrice $productPrice): bool | |||
{ | |||
return !$productPrice->id_user | |||
&& !$productPrice->id_point_sale | |||
&& !$productPrice->id_user_group | |||
&& $productPrice->from_quantity; | |||
} | |||
} |
@@ -38,7 +38,8 @@ | |||
"yiisoft/yii2-debug": "*", | |||
"yiisoft/yii2-gii": "*", | |||
"yiisoft/yii2-faker": "*", | |||
"codeception/codeception": "^2.3" | |||
"codeception/codeception": "^2.3", | |||
"phpstan/phpstan": "^1.9" | |||
}, | |||
"config": { | |||
"process-timeout": 1800, |
@@ -4,7 +4,7 @@ | |||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | |||
"This file is @generated automatically" | |||
], | |||
"content-hash": "78a16f604e3b8e2cb623f7204619682f", | |||
"content-hash": "85c783330a1d88a3ed3c4674e84d10ba", | |||
"packages": [ | |||
{ | |||
"name": "2amigos/yii2-chartjs-widget", | |||
@@ -3554,6 +3554,65 @@ | |||
}, | |||
"time": "2020-03-05T15:02:03+00:00" | |||
}, | |||
{ | |||
"name": "phpstan/phpstan", | |||
"version": "1.9.17", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/phpstan/phpstan.git", | |||
"reference": "204e459e7822f2c586463029f5ecec31bb45a1f2" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/204e459e7822f2c586463029f5ecec31bb45a1f2", | |||
"reference": "204e459e7822f2c586463029f5ecec31bb45a1f2", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": "^7.2|^8.0" | |||
}, | |||
"conflict": { | |||
"phpstan/phpstan-shim": "*" | |||
}, | |||
"bin": [ | |||
"phpstan", | |||
"phpstan.phar" | |||
], | |||
"type": "library", | |||
"autoload": { | |||
"files": [ | |||
"bootstrap.php" | |||
] | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"description": "PHPStan - PHP Static Analysis Tool", | |||
"keywords": [ | |||
"dev", | |||
"static analysis" | |||
], | |||
"support": { | |||
"issues": "https://github.com/phpstan/phpstan/issues", | |||
"source": "https://github.com/phpstan/phpstan/tree/1.9.17" | |||
}, | |||
"funding": [ | |||
{ | |||
"url": "https://github.com/ondrejmirtes", | |||
"type": "github" | |||
}, | |||
{ | |||
"url": "https://github.com/phpstan", | |||
"type": "github" | |||
}, | |||
{ | |||
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", | |||
"type": "tidelift" | |||
} | |||
], | |||
"time": "2023-02-08T12:25:00+00:00" | |||
}, | |||
{ | |||
"name": "phpunit/php-code-coverage", | |||
"version": "6.1.4", |