@@ -121,284 +121,4 @@ class Document extends ActiveRecordCommon implements DocumentInterface | |||
->joinWith($defaultOptionsSearch['join_with']) | |||
->orderBy('distribution.date ASC'); | |||
} | |||
/* | |||
* Méthodes | |||
*/ | |||
public function generateReference() | |||
{ | |||
$class = $this->getClass(); | |||
$classLower = strtolower($class); | |||
if ($classLower == 'deliverynote') { | |||
$classLower = 'delivery_note'; | |||
} | |||
$prefix = Producer::getConfig('document_' . $classLower . '_prefix'); | |||
$oneDocumentExist = $class::searchOne(['status' => Document::STATUS_VALID], ['orderby' => 'reference DESC']); | |||
if ($oneDocumentExist) { | |||
$reference = $oneDocumentExist->reference; | |||
$pattern = '#([A-Z]+)?([0-9]+)#'; | |||
preg_match($pattern, $reference, $matches, PREG_OFFSET_CAPTURE); | |||
$sizeNumReference = strlen($matches[2][0]); | |||
$numReference = ((int)$matches[2][0]) + 1; | |||
$numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT); | |||
return $prefix . $numReference; | |||
} else { | |||
$firstReference = Producer::getConfig('document_' . $classLower . '_first_reference'); | |||
if (strlen($firstReference) > 0) { | |||
return $firstReference; | |||
} else { | |||
return $prefix . '00001'; | |||
} | |||
} | |||
} | |||
public function downloadPdf($regenerate = false) | |||
{ | |||
$filenameComplete = $this->getFilenameComplete(); | |||
if (!file_exists($filenameComplete) || $this->isStatusDraft() || $regenerate) { | |||
$this->generatePdf(Pdf::DEST_FILE); | |||
} | |||
if (file_exists($filenameComplete)) { | |||
return Yii::$app->response->sendFile($filenameComplete, $this->getFilename(), ['inline' => true]); | |||
} else { | |||
throw new ErrorException('File ' . $filenameComplete . ' not found'); | |||
} | |||
} | |||
public function generatePdf($destination) | |||
{ | |||
$producer = $this->producer; | |||
$content = Yii::$app->controller->renderPartial('/document/download', [ | |||
'producer' => $producer, | |||
'document' => $this | |||
]); | |||
$contentFooter = '<div id="footer">'; | |||
$contentFooter .= '<div class="infos-bottom">' . Html::encode($producer->document_infos_bottom) . '</div>'; | |||
if ($this->isStatusValid() || $this->isStatusDraft()) { | |||
$contentFooter .= '<div class="reference-document">'; | |||
if ($this->isStatusValid()) { | |||
$contentFooter .= $this->getType() . ' N°' . $this->reference; | |||
} | |||
if ($this->isStatusDraft()) { | |||
$contentFooter .= $this->getType() . ' non validé'; | |||
if ($this->getType() == 'Facture') { | |||
$contentFooter .= 'e'; | |||
} | |||
} | |||
$contentFooter .= '</div>'; | |||
} | |||
$contentFooter .= '</div>'; | |||
$marginBottom = 10; | |||
if (strlen(Producer::getConfig('document_infos_bottom')) > 0) { | |||
$marginBottom = 40; | |||
} | |||
$this->initDirectoryPdf(); | |||
$pdf = new Pdf([ | |||
'mode' => Pdf::MODE_UTF8, | |||
'format' => Pdf::FORMAT_A4, | |||
'orientation' => Pdf::ORIENT_PORTRAIT, | |||
'destination' => $destination, | |||
'content' => $content, | |||
'filename' => $this->getFilenameComplete(), | |||
'cssFile' => Yii::getAlias('@webroot/css/document/download.css'), | |||
'marginBottom' => $marginBottom, | |||
'methods' => [ | |||
'SetHTMLFooter' => $contentFooter | |||
] | |||
]); | |||
return $pdf->render(); | |||
} | |||
public function send() | |||
{ | |||
if (isset($this->user) && strlen($this->user->email) > 0) { | |||
$producer = GlobalParam::getCurrentProducer(); | |||
$subjectEmail = $this->getType(); | |||
if ($this->isStatusValid()) { | |||
$subjectEmail .= ' N°' . $this->reference; | |||
} | |||
$email = Yii::$app->mailer->compose( | |||
[ | |||
'html' => 'sendDocument-html', | |||
'text' => 'sendDocument-text' | |||
], [ | |||
'document' => $this, | |||
]) | |||
->setTo($this->user->email) | |||
->setFrom([$producer->getEmailOpendistrib() => $producer->name]) | |||
->setSubject('[' . $producer->name . '] ' . $subjectEmail); | |||
$this->generatePdf(Pdf::DEST_FILE); | |||
$email->attach($this->getFilenameComplete()); | |||
return $email->send(); | |||
} | |||
return false; | |||
} | |||
public function changeStatus($status) | |||
{ | |||
if ($status == Document::STATUS_VALID) { | |||
$this->status = $status; | |||
$this->reference = $this->generateReference(); | |||
} | |||
} | |||
public function getStatusWording() | |||
{ | |||
return ($this->status == self::STATUS_DRAFT) ? 'Brouillon' : 'Validé'; | |||
} | |||
public function getStatusCssClass() | |||
{ | |||
return ($this->status == self::STATUS_DRAFT) ? 'default' : 'success'; | |||
} | |||
public function getHtmlLabel() | |||
{ | |||
$label = $this->getStatusWording(); | |||
$classLabel = $this->getStatusCssClass(); | |||
return '<span class="label label-' . $classLabel . '">' . $label . '</span>'; | |||
} | |||
public function isStatus($status) | |||
{ | |||
return $this->status == $status; | |||
} | |||
public function isStatusDraft() | |||
{ | |||
return $this->isStatus(self::STATUS_DRAFT); | |||
} | |||
public function isStatusValid() | |||
{ | |||
return $this->isStatus(self::STATUS_VALID); | |||
} | |||
public function getProductsOrders() | |||
{ | |||
$productsOrdersArray = []; | |||
$ordersArray = $this->orders; | |||
if ($ordersArray && count($ordersArray)) { | |||
foreach ($ordersArray as $order) { | |||
foreach ($order->productOrder as $productOrder) { | |||
if ($productOrder->product) { | |||
$indexProductOrder = $productOrder->product->order; | |||
$newProductOrder = clone $productOrder; | |||
if (!isset($productsOrdersArray[$indexProductOrder])) { | |||
$productsOrdersArray[$indexProductOrder] = [$newProductOrder]; | |||
} else { | |||
$productOrderMatch = false; | |||
foreach ($productsOrdersArray[$indexProductOrder] as &$theProductOrder) { | |||
if ($theProductOrder->unit == $productOrder->unit | |||
&& $theProductOrder->price == $productOrder->price | |||
&& $theProductOrder->invoice_price == $productOrder->invoice_price) { | |||
$theProductOrder->quantity += $productOrder->quantity; | |||
$productOrderMatch = true; | |||
} | |||
} | |||
if (!$productOrderMatch) { | |||
$productsOrdersArray[$indexProductOrder][] = $newProductOrder; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// tri des orderProduct par product.order | |||
ksort($productsOrdersArray); | |||
return $productsOrdersArray; | |||
} | |||
public function isDisplayOrders() | |||
{ | |||
$displayOrders = ($this->getClass() == 'Invoice') ? | |||
Producer::getConfig('document_display_orders_invoice') : | |||
Producer::getConfig('document_display_orders_delivery_note'); | |||
return $displayOrders; | |||
} | |||
public function getAliasDirectoryBase() | |||
{ | |||
return '@app/web/pdf/' . $this->id_producer . '/'; | |||
} | |||
public function initDirectoryPdf() | |||
{ | |||
$aliasDirectoryBase = $this->getAliasDirectoryBase(); | |||
$directoryPdf = Yii::getAlias($aliasDirectoryBase); | |||
if (!file_exists($directoryPdf)) { | |||
mkdir($directoryPdf, 0755); | |||
} | |||
} | |||
public function getFilename() | |||
{ | |||
$filename = $this->getType() . '-'; | |||
if($this->isStatusValid()) { | |||
$filename .= $this->reference; | |||
} | |||
elseif($this->isStatusDraft()) { | |||
$filename .= 'Brouillon-'.$this->id; | |||
} | |||
$filename .= '.pdf'; | |||
return $filename; | |||
} | |||
public function getFilenameComplete() | |||
{ | |||
return Yii::getAlias($this->getAliasDirectoryBase() . $this->getFilename()); | |||
} | |||
public function isInvoicePrice() | |||
{ | |||
return $this->getClass() == 'Invoice' || $this->getClass() == 'DeliveryNote'; | |||
} | |||
public function isTaxCalculationMethodSumOfRoundings() | |||
{ | |||
return $this->tax_calculation_method == self::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS; | |||
} | |||
public function isTaxCalculationMethodRoundingOfTheSum() | |||
{ | |||
return $this->tax_calculation_method == self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM; | |||
} | |||
public function initTaxCalculationMethod() | |||
{ | |||
$producerTaxCalculationMethod = Producer::getConfig('option_tax_calculation_method'); | |||
if ($producerTaxCalculationMethod) { | |||
$this->tax_calculation_method = $producerTaxCalculationMethod; | |||
} else { | |||
$this->tax_calculation_method = self::TAX_CALCULATION_METHOD_DEFAULT; | |||
} | |||
} | |||
} |
@@ -4,8 +4,71 @@ namespace common\logic\Document\Document; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\Producer\Producer\ProducerRepository; | |||
use kartik\mpdf\Pdf; | |||
use yii\helpers\Html; | |||
class DocumentBuilder extends BaseService implements BuilderInterface | |||
{ | |||
protected DocumentSolver $documentSolver; | |||
protected ProducerRepository $producerRepository; | |||
public function __construct() | |||
{ | |||
$this->documentSolver = $this->loadService(DocumentSolver::class); | |||
$this->producerRepository = $this->loadService(ProducerRepository::class); | |||
} | |||
public function generateReference(DocumentInterface $document): void | |||
{ | |||
$class = $document->getClass(); | |||
$classLower = strtolower($class); | |||
if ($classLower == 'deliverynote') { | |||
$classLower = 'delivery_note'; | |||
} | |||
$prefix = $this->producerRepository->getConfig('document_' . $classLower . '_prefix'); | |||
$oneDocumentExist = $class::searchOne(['status' => Document::STATUS_VALID], ['orderby' => 'reference DESC']); | |||
if ($oneDocumentExist) { | |||
$referenceDocument = $oneDocumentExist->reference; | |||
$pattern = '#([A-Z]+)?([0-9]+)#'; | |||
preg_match($pattern, $referenceDocument, $matches, PREG_OFFSET_CAPTURE); | |||
$sizeNumReference = strlen($matches[2][0]); | |||
$numReference = ((int)$matches[2][0]) + 1; | |||
$numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT); | |||
$reference = $prefix . $numReference; | |||
} else { | |||
$firstReference = $this->producerRepository->getConfig('document_' . $classLower . '_first_reference'); | |||
if (strlen($firstReference) > 0) { | |||
$reference = $firstReference; | |||
} else { | |||
$reference = $prefix . '00001'; | |||
} | |||
} | |||
$document->reference = $reference; | |||
} | |||
public function changeStatus(DocumentInterface $document, string $status): void | |||
{ | |||
if ($status == Document::STATUS_VALID) { | |||
$document->status = $status; | |||
$this->generateReference($document); | |||
} | |||
} | |||
public function initTaxCalculationMethod(DocumentInterface $document): void | |||
{ | |||
$producerTaxCalculationMethod = $this->producerRepository->getConfig('option_tax_calculation_method'); | |||
if ($producerTaxCalculationMethod) { | |||
$document->tax_calculation_method = $producerTaxCalculationMethod; | |||
} else { | |||
$document->tax_calculation_method = Document::TAX_CALCULATION_METHOD_DEFAULT; | |||
} | |||
} | |||
} |
@@ -4,6 +4,7 @@ namespace common\logic\Document\Document; | |||
use common\logic\BaseService; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\SolverInterface; | |||
class DocumentSolver extends BaseService implements SolverInterface | |||
@@ -116,4 +117,117 @@ class DocumentSolver extends BaseService implements SolverInterface | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); | |||
} | |||
public function getStatusWording(DocumentInterface $document): string | |||
{ | |||
return ($document->status == Document::STATUS_DRAFT) ? 'Brouillon' : 'Validé'; | |||
} | |||
public function getStatusCssClass(DocumentInterface $document): string | |||
{ | |||
return ($document->status == Document::STATUS_DRAFT) ? 'default' : 'success'; | |||
} | |||
public function getHtmlLabel(DocumentInterface $document) | |||
{ | |||
$label = $this->getStatusWording($document); | |||
$classLabel = $this->getStatusCssClass($document); | |||
return '<span class="label label-' . $classLabel . '">' . $label . '</span>'; | |||
} | |||
public function isStatus(DocumentInterface $document, string $status): bool | |||
{ | |||
return $document->status == $status; | |||
} | |||
public function isStatusDraft(DocumentInterface $document): bool | |||
{ | |||
return $this->isStatus($document, Document::STATUS_DRAFT); | |||
} | |||
public function isStatusValid(DocumentInterface $document): bool | |||
{ | |||
return $this->isStatus($document, Document::STATUS_VALID); | |||
} | |||
public function getProductsOrders(DocumentInterface $document): array | |||
{ | |||
$productsOrdersArray = []; | |||
$ordersArray = $document->orders; | |||
if ($ordersArray && count($ordersArray)) { | |||
foreach ($ordersArray as $order) { | |||
foreach ($order->productOrder as $productOrder) { | |||
if ($productOrder->product) { | |||
$indexProductOrder = $productOrder->product->order; | |||
$newProductOrder = clone $productOrder; | |||
if (!isset($productsOrdersArray[$indexProductOrder])) { | |||
$productsOrdersArray[$indexProductOrder] = [$newProductOrder]; | |||
} else { | |||
$productOrderMatch = false; | |||
foreach ($productsOrdersArray[$indexProductOrder] as &$theProductOrder) { | |||
if ($theProductOrder->unit == $productOrder->unit | |||
&& $theProductOrder->price == $productOrder->price | |||
&& $theProductOrder->invoice_price == $productOrder->invoice_price) { | |||
$theProductOrder->quantity += $productOrder->quantity; | |||
$productOrderMatch = true; | |||
} | |||
} | |||
if (!$productOrderMatch) { | |||
$productsOrdersArray[$indexProductOrder][] = $newProductOrder; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// tri des orderProduct par product.order | |||
ksort($productsOrdersArray); | |||
return $productsOrdersArray; | |||
} | |||
public function getAliasDirectoryBase(DocumentInterface $document): string | |||
{ | |||
return '@app/web/pdf/' . $document->id_producer . '/'; | |||
} | |||
public function getFilename(DocumentInterface $document): string | |||
{ | |||
$filename = $document->getType() . '-'; | |||
if($this->isStatusValid($document)) { | |||
$filename .= $document->reference; | |||
} | |||
elseif($this->isStatusDraft($document)) { | |||
$filename .= 'Brouillon-'.$document->id; | |||
} | |||
$filename .= '.pdf'; | |||
return $filename; | |||
} | |||
public function getFilenameComplete(DocumentInterface $document): string | |||
{ | |||
return \Yii::getAlias($this->getAliasDirectoryBase($document) . $this->getFilename($document)); | |||
} | |||
public function isInvoicePrice(DocumentInterface $document): bool | |||
{ | |||
return $this->getClass() == 'Invoice' || $this->getClass() == 'DeliveryNote'; | |||
} | |||
public function isTaxCalculationMethodSumOfRoundings(DocumentInterface $document): bool | |||
{ | |||
return $document->tax_calculation_method == self::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS; | |||
} | |||
public function isTaxCalculationMethodRoundingOfTheSum(DocumentInterface $document): bool | |||
{ | |||
return $document->tax_calculation_method == self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM; | |||
} | |||
} |
@@ -2,10 +2,130 @@ | |||
namespace common\logic\Document\Document; | |||
use common\helpers\GlobalParam; | |||
use common\logic\BaseService; | |||
use common\logic\Producer\Producer\ProducerRepository; | |||
use common\logic\Producer\Producer\ProducerSolver; | |||
use common\logic\UtilsInterface; | |||
use kartik\mpdf\Pdf; | |||
use yii\base\ErrorException; | |||
use yii\helpers\Html; | |||
class DocumentUtils extends BaseService implements UtilsInterface | |||
{ | |||
protected DocumentSolver $documentSolver; | |||
protected DocumentBuilder $documentBuilder; | |||
protected ProducerSolver $producerSolver; | |||
protected ProducerRepository $producerRepository; | |||
public function __construct() | |||
{ | |||
$this->documentSolver = $this->loadService(DocumentSolver::class); | |||
$this->documentBuilder = $this->loadService(DocumentBuilder::class); | |||
$this->producerSolver = $this->loadService(ProducerSolver::class); | |||
$this->producerRepository = $this->loadService(ProducerRepository::class); | |||
} | |||
public function generatePdf(DocumentInterface $document, string $destination): string | |||
{ | |||
$producer = $document->producer; | |||
$content = \Yii::$app->controller->renderPartial('/document/download', [ | |||
'producer' => $producer, | |||
'document' => $this | |||
]); | |||
$contentFooter = '<div id="footer">'; | |||
$contentFooter .= '<div class="infos-bottom">' . Html::encode($producer->document_infos_bottom) . '</div>'; | |||
if ($this->documentSolver->isStatusValid($document) || $this->documentSolver->isStatusDraft($document)) { | |||
$contentFooter .= '<div class="reference-document">'; | |||
if ($this->documentSolver->isStatusValid($document)) { | |||
$contentFooter .= $this->getType() . ' N°' . $document->reference; | |||
} | |||
if ($this->documentSolver->isStatusDraft($document)) { | |||
$contentFooter .= $document->getType() . ' non validé'; | |||
if ($document->getType() == 'Facture') { | |||
$contentFooter .= 'e'; | |||
} | |||
} | |||
$contentFooter .= '</div>'; | |||
} | |||
$contentFooter .= '</div>'; | |||
$marginBottom = 10; | |||
if (strlen($this->producerRepository->getConfig('document_infos_bottom')) > 0) { | |||
$marginBottom = 40; | |||
} | |||
$this->initDirectoryPdf($document); | |||
$pdf = new Pdf([ | |||
'mode' => Pdf::MODE_UTF8, | |||
'format' => Pdf::FORMAT_A4, | |||
'orientation' => Pdf::ORIENT_PORTRAIT, | |||
'destination' => $destination, | |||
'content' => $content, | |||
'filename' => $this->documentSolver->getFilenameComplete($document), | |||
'cssFile' => \Yii::getAlias('@webroot/css/document/download.css'), | |||
'marginBottom' => $marginBottom, | |||
'methods' => [ | |||
'SetHTMLFooter' => $contentFooter | |||
] | |||
]); | |||
return $pdf->render(); | |||
} | |||
public function initDirectoryPdf(DocumentInterface $document): void | |||
{ | |||
$aliasDirectoryBase = $this->documentSolver->getAliasDirectoryBase($document); | |||
$directoryPdf = \Yii::getAlias($aliasDirectoryBase); | |||
if (!file_exists($directoryPdf)) { | |||
mkdir($directoryPdf, 0755); | |||
} | |||
} | |||
public function downloadPdf(DocumentInterface $document, $regenerate = false) | |||
{ | |||
$filenameComplete = $this->documentSolver->getFilenameComplete($document); | |||
if (!file_exists($filenameComplete) || $this->documentSolver->isStatusDraft($document) || $regenerate) { | |||
$this->generatePdf($document, Pdf::DEST_FILE); | |||
} | |||
if (file_exists($filenameComplete)) { | |||
return \Yii::$app->response->sendFile($filenameComplete, $this->documentSolver->getFilename($document), ['inline' => true]); | |||
} else { | |||
throw new ErrorException('File ' . $filenameComplete . ' not found'); | |||
} | |||
} | |||
public function send(DocumentInterface $document) | |||
{ | |||
if (isset($document->user) && strlen($document->user->email) > 0) { | |||
$producer = GlobalParam::getCurrentProducer(); | |||
$subjectEmail = $document->getType(); | |||
if ($this->documentSolver->isStatusValid($document)) { | |||
$subjectEmail .= ' N°' . $document->reference; | |||
} | |||
$email = \Yii::$app->mailer->compose( | |||
[ | |||
'html' => 'sendDocument-html', | |||
'text' => 'sendDocument-text' | |||
], [ | |||
'document' => $this, | |||
]) | |||
->setTo($document->user->email) | |||
->setFrom([$producer->getEmailOpendistrib() => $producer->name]) | |||
->setSubject('[' . $producer->name . '] ' . $subjectEmail); | |||
$this->documentBuilder->generatePdf($document, Pdf::DEST_FILE); | |||
$email->attach($this->documentSolver->getFilenameComplete($document)); | |||
return $email->send(); | |||
} | |||
return false; | |||
} | |||
} |
@@ -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\Invoice; | |||
@@ -42,52 +42,25 @@ use common\logic\Document\Document\Document; | |||
/** | |||
* This is the model class for table "invoice". | |||
* | |||
* @property integer $id | |||
* @property string $name | |||
* @property string $reference | |||
* @property string $date | |||
* @property string $comment | |||
* @property integer $id_user | |||
* @property string $address | |||
* @property string $city | |||
* @property string $postcode | |||
*/ | |||
class Invoice extends Document | |||
{ | |||
public $deliveryNotes ; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'invoice'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->relationOrders('id_invoice') ; | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => ['user AS user_invoice', 'producer'], | |||
'orderby' => 'date ASC', | |||
'attribute_id_producer' => 'invoice.id_producer' | |||
]; | |||
} | |||
public $deliveryNotes; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'invoice'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->relationOrders('id_invoice'); | |||
} | |||
} |
@@ -7,5 +7,13 @@ use common\logic\RepositoryInterface; | |||
class InvoiceRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => ['user AS user_invoice', 'producer'], | |||
'orderby' => 'date ASC', | |||
'attribute_id_producer' => 'invoice.id_producer' | |||
]; | |||
} | |||
} |
@@ -1,39 +1,39 @@ | |||
<?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\Quotation; | |||
@@ -42,50 +42,24 @@ use common\logic\Document\Document\Document; | |||
/** | |||
* This is the model class for table "quotation". | |||
* | |||
* @property integer $id | |||
* @property string $name | |||
* @property string $reference | |||
* @property string $date | |||
* @property string $comment | |||
* @property integer $id_user | |||
* @property string $address | |||
* @property string $city | |||
* @property string $postcode | |||
*/ | |||
class Quotation extends Document | |||
{ | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'quotation'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->relationOrders('id_quotation') ; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'quotation'; | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => ['user AS user_quotation', 'producer'], | |||
'orderby' => 'date ASC', | |||
'attribute_id_producer' => 'quotation.id_producer' | |||
]; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->relationOrders('id_quotation'); | |||
} | |||
} |
@@ -7,5 +7,13 @@ use common\logic\RepositoryInterface; | |||
class QuotationRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => ['user AS user_quotation', 'producer'], | |||
'orderby' => 'date ASC', | |||
'attribute_id_producer' => 'quotation.id_producer' | |||
]; | |||
} | |||
} |
@@ -2,16 +2,324 @@ | |||
namespace common\logic\Order\Order; | |||
use common\helpers\GlobalParam; | |||
use common\helpers\Price; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\SolverInterface; | |||
use common\logic\Document\Document\Document; | |||
use common\logic\Order\OrderStatusHistory\OrderStatusHistoryBuilder; | |||
use common\logic\Order\ProductOrder\ProductOrder; | |||
use common\logic\Order\ProductOrder\ProductOrderBuilder; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\Producer\Producer\ProducerRepository; | |||
use common\logic\User\CreditHistory\CreditHistory; | |||
use common\logic\User\CreditHistory\CreditHistoryBuilder; | |||
use common\logic\User\CreditHistory\CreditHistoryRepository; | |||
use common\logic\User\User\UserSolver; | |||
use yii\web\NotFoundHttpException; | |||
class OrderBuilder extends BaseService implements BuilderInterface | |||
{ | |||
protected UserSolver $userSolver; | |||
protected OrderSolver $orderSolver; | |||
protected CreditHistoryRepository $creditHistoryRepository; | |||
protected ProducerRepository $producerRepository; | |||
protected CreditHistoryBuilder $creditHistoryBuilder; | |||
protected ProductOrderBuilder $productOrderBuilder; | |||
protected OrderStatusHistoryBuilder $orderStatusHistoryBuilder; | |||
protected OrderRepository $orderRepository; | |||
public function __construct() | |||
{ | |||
$this->userSolver = $this->loadService(UserSolver::class); | |||
$this->orderSolver = $this->loadService(OrderSolver::class); | |||
$this->creditHistoryRepository = $this->loadService(CreditHistoryRepository::class); | |||
$this->producerRepository = $this->loadService(ProducerRepository::class); | |||
$this->creditHistoryBuilder = $this->loadService(CreditHistoryBuilder::class); | |||
$this->productOrderBuilder = $this->loadService(ProductOrderBuilder::class); | |||
$this->orderStatusHistoryBuilder = $this->loadService(OrderStatusHistoryBuilder::class); | |||
$this->orderRepository = $this->loadService(OrderRepository::class); | |||
} | |||
public function instanciate(): Order | |||
{ | |||
$order = new Order(); | |||
return $order; | |||
} | |||
/** | |||
* Initialise le montant total, le montant déjà payé et le poids de la commande. | |||
*/ | |||
public function init(Order $order, $taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT) | |||
{ | |||
$this->initAmount($order, $taxCalculationMethod); | |||
$this->initPaidAmount($order); | |||
return $this; | |||
} | |||
/** | |||
* Initialise le montant de la commande. | |||
*/ | |||
public function initAmount(Order $order, $taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT) | |||
{ | |||
$order->amount = 0; | |||
$order->amount_with_tax = 0; | |||
$order->amount_vat = []; | |||
$order->invoice_amount = 0; | |||
$order->invoice_amount_with_tax = 0; | |||
$order->invoice_amount_vat = []; | |||
$order->weight = 0; | |||
if (isset($order->productOrder)) { | |||
foreach ($order->productOrder as $productOrder) { | |||
$this->addAmount($order, Order::AMOUNT_TOTAL, $productOrder, $taxCalculationMethod); | |||
$this->addAmount($order, Order::INVOICE_AMOUNT_TOTAL, $productOrder, $taxCalculationMethod); | |||
$this->addWeight($order, $productOrder); | |||
} | |||
} | |||
} | |||
public function addWeight(Order $order, ProductOrder $productOrder): void | |||
{ | |||
if ($productOrder->unit == 'piece') { | |||
if (isset($productOrder->product)) { | |||
$order->weight += ($productOrder->quantity * $productOrder->product->weight) / 1000; | |||
} | |||
} else { | |||
$order->weight += $productOrder->quantity; | |||
} | |||
} | |||
public function addAmount(Order $order, $typeTotal, $productOrder, $taxCalculationMethod) | |||
{ | |||
$fieldNameAmount = $this->getFieldNameAmount($typeTotal); | |||
$fieldNameAmountWithTax = $this->getFieldNameAmount($typeTotal, 'with_tax'); | |||
$price = $productOrder->getPriceByTypeTotal($typeTotal); | |||
$order->$fieldNameAmount += $price * $productOrder->quantity; | |||
$order->$fieldNameAmountWithTax += Price::getPriceWithTax( | |||
$price, | |||
$productOrder->taxRate->value, | |||
$taxCalculationMethod | |||
) * $productOrder->quantity; | |||
$order->addVat($order, $typeTotal, $price * $productOrder->quantity, $productOrder->taxRate, $taxCalculationMethod); | |||
} | |||
public function addVat($typeTotal, $priceTotalWithoutTax, $taxRate, $taxCalculationMethod) | |||
{ | |||
$fieldName = $this->getFieldNameAmount($typeTotal, 'vat'); | |||
if (!isset($this->$fieldName[$taxRate->id])) { | |||
$this->$fieldName[$taxRate->id] = 0; | |||
} | |||
$this->$fieldName[$taxRate->id] += Price::getVat($priceTotalWithoutTax, $taxRate->value, $taxCalculationMethod); | |||
} | |||
/** | |||
* Initialise le montant payé de la commande et le retourne. | |||
*/ | |||
public function initPaidAmount(Order $order): void | |||
{ | |||
if (isset($order->creditHistory)) { | |||
$history = $order->creditHistory; | |||
} else { | |||
$history = $this->creditHistoryRepository->getByOrder($order); | |||
} | |||
$order->paid_amount = 0; | |||
if (count($history)) { | |||
foreach ($history as $ch) { | |||
if ($ch->type == CreditHistory::TYPE_PAYMENT) { | |||
$order->paid_amount += $ch->amount; | |||
} elseif ($ch->type == CreditHistory::TYPE_REFUND) { | |||
$order->paid_amount -= $ch->amount; | |||
} | |||
} | |||
} | |||
} | |||
public function delete(Order $order, $force = false) | |||
{ | |||
// remboursement si l'utilisateur a payé pour cette commande | |||
$amountPaid = $this->orderSolver->getAmount(Order::AMOUNT_PAID); | |||
if ($amountPaid > 0.01) { | |||
$this->creditHistoryBuilder->create( | |||
CreditHistory::TYPE_REFUND, | |||
$amountPaid, | |||
GlobalParam::getCurrentProducer(), | |||
$order->user, | |||
$this->userSolver->getCurrent(), | |||
$order | |||
); | |||
} | |||
// delete | |||
if ($this->producerRepository->getConfig('option_behavior_cancel_order') == Producer::BEHAVIOR_DELETE_ORDER_DELETE || | |||
($this->producerRepository->getConfig('option_behavior_cancel_order') == Producer::BEHAVIOR_DELETE_ORDER_STATUS && strlen($order->date_delete)) | |||
|| $force) { | |||
$this->productOrderBuilder->deleteByOrder($order); | |||
return $order->delete(); | |||
} | |||
// status 'delete' | |||
elseif ($this->producerRepository->getConfig('option_behavior_cancel_order') == Producer::BEHAVIOR_DELETE_ORDER_STATUS) { | |||
$order->date_delete = date('Y-m-d H:i:s'); | |||
return $order->save(); | |||
} | |||
} | |||
/** | |||
* Ajuste le crédit pour que la commande soit payée. | |||
*/ | |||
public function processCredit(Order $order): void | |||
{ | |||
if ($order->id_user) { | |||
$paymentStatus = $this->orderSolver->getPaymentStatus($order); | |||
if ($paymentStatus == Order::PAYMENT_PAID) { | |||
return; | |||
} elseif ($paymentStatus == Order::PAYMENT_SURPLUS) { | |||
$type = CreditHistory::TYPE_REFUND; | |||
$amount = $this->orderSolver->getAmount($order, Order::AMOUNT_SURPLUS); | |||
} elseif ($paymentStatus == Order::PAYMENT_UNPAID) { | |||
$type = CreditHistory::TYPE_PAYMENT; | |||
$amount = $this->orderSolver->getAmount($order, Order::AMOUNT_REMAINING); | |||
} | |||
$this->creditHistoryBuilder->create( | |||
$type, | |||
$amount, | |||
GlobalParam::getCurrentProducer(), | |||
$order->user, | |||
$this->userSolver->getCurrent(), | |||
$order | |||
); | |||
} | |||
} | |||
// setTillerSynchronization | |||
public function updateTillerSynchronization(Order $order) | |||
{ | |||
$paymentStatus = $order->getPaymentStatus(); | |||
if ($paymentStatus == Order::PAYMENT_PAID) { | |||
$order->tiller_synchronization = 1; | |||
} else { | |||
$order->tiller_synchronization = 0; | |||
} | |||
$order->save(); | |||
return $order; | |||
} | |||
/** | |||
* Changement de statut d'une commande. | |||
*/ | |||
public function changeOrderStatus(Order $order, string $newStatus, string $origin): void | |||
{ | |||
$orderStatusArray = GlobalParam::get('orderStatus'); | |||
$userCurrent = $this->userSolver->getCurrent(); | |||
switch ($newStatus) { | |||
case 'new-order' : | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
break; | |||
case 'waiting-paiement-on-delivery': | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
case 'waiting-paiement-by-credit': | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
case 'paid-by-credit': | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
case 'waiting-delevery' : | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
case 'delivered': | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
case 'refunded': | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
case 'cancel': | |||
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) { | |||
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin); | |||
$order->status = $newStatus; | |||
$order->save(); | |||
} | |||
break; | |||
default: | |||
throw new NotFoundHttpException('Statut de commande inconnu.'); | |||
} | |||
} | |||
// initReference | |||
public function generateReference(Order $order) | |||
{ | |||
$idProducer = GlobalParam::getCurrentProducerId(); | |||
$producer = $this->producerRepository->getOneById($idProducer); | |||
if (!$order->reference && $producer->option_order_reference_type == Producer::ORDER_REFERENCE_TYPE_YEARLY) { | |||
$lastOrder = $this->orderRepository->getOneLastOfYear(); | |||
if ($lastOrder && $lastOrder->reference && strlen($lastOrder->reference) > 0) { | |||
$pattern = '#A([0-9]+)C([0-9]+)#'; | |||
preg_match($pattern, $lastOrder->reference, $matches, PREG_OFFSET_CAPTURE); | |||
$sizeNumReference = strlen($matches[2][0]); | |||
$numReference = ((int)$matches[2][0]) + 1; | |||
$numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT); | |||
$order->reference = 'A' . $matches[1][0] . 'C' . $numReference; | |||
} else { | |||
$order->reference = 'A' . date('y') . 'C0001'; | |||
} | |||
$order->save(); | |||
} | |||
} | |||
// initInvoicePrices | |||
public function updateInvoicePrices(Order $order, $params = []): void | |||
{ | |||
foreach ($order->productOrder as $productOrder) { | |||
if ($productOrder->product) { | |||
$this->productOrderBuilder->updateInvoicePrice($productOrder, $params); | |||
} | |||
} | |||
} | |||
} |
@@ -4,10 +4,27 @@ namespace common\logic\Order\Order; | |||
use common\logic\BaseService; | |||
use common\logic\Distribution\Distribution\Distribution; | |||
use common\logic\Order\ProductOrder\ProductOrder; | |||
use common\logic\PointSale\PointSale\ProductOrderRepository; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\Producer\Producer\ProducerRepository; | |||
use common\logic\Product\Product\Product; | |||
use common\logic\RepositoryInterface; | |||
use yii\helpers\Html; | |||
class OrderRepository extends BaseService implements RepositoryInterface | |||
{ | |||
protected ProductOrderRepository $productOrderRepository; | |||
protected ProducerRepository $producerRepository; | |||
protected OrderSolver $orderSolver; | |||
public function __construct() | |||
{ | |||
$this->productOrderRepository = $this->loadService(ProductOrderRepository::class); | |||
$this->producerRepository = $this->loadService(ProducerRepository::class); | |||
$this->orderSolver = $this->loadService(OrderSolver::class); | |||
} | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
@@ -24,6 +41,44 @@ class OrderRepository extends BaseService implements RepositoryInterface | |||
]; | |||
} | |||
public function getOneById(Order $order) | |||
{ | |||
return Order::searchOne(['order.id' => $order->id]);; | |||
} | |||
/** | |||
* Recherche et initialise des commandes. | |||
*/ | |||
public function searchBy($params = [], $options = []) | |||
{ | |||
$orders = Order::searchBy($params, $options); | |||
/* | |||
* Initialisation des commandes | |||
*/ | |||
if (is_array($orders)) { | |||
if (count($orders)) { | |||
foreach ($orders as $order) { | |||
if (is_a($order, 'common\logic\Order\Order\Order')) { | |||
$order->init(); | |||
} | |||
} | |||
return $orders; | |||
} | |||
} else { | |||
$order = $orders; | |||
if (is_a($order, 'common\logic\Order\Order\Order')) { | |||
return $order->init(); | |||
} // count | |||
else { | |||
return $order; | |||
} | |||
} | |||
return false; | |||
} | |||
public function getByDistribution(Distribution $distribution, string $conditionAppend = '') | |||
{ | |||
return Order::searchAll([ | |||
@@ -34,4 +89,152 @@ class OrderRepository extends BaseService implements RepositoryInterface | |||
'conditions' => 'date_delete IS NULL ' . $conditionAppend | |||
]); | |||
} | |||
/** | |||
* Retourne les informations relatives à la commande au format JSON. | |||
*/ | |||
public function getDataJson(Order $order): string | |||
{ | |||
$jsonOrder = []; | |||
if ($order) { | |||
$jsonOrder = [ | |||
'products' => [], | |||
'amount' => $order->amount, | |||
'str_amount' => $order->getAmountWithTax(Order::AMOUNT_TOTAL, true), | |||
'paid_amount' => $order->getAmount(Order::AMOUNT_PAID), | |||
'comment' => $order->comment, | |||
]; | |||
foreach ($order->productOrder as $productOrder) { | |||
$jsonOrder['products'][$productOrder->id_product] = $productOrder->quantity; | |||
} | |||
} | |||
return json_encode($jsonOrder); | |||
} | |||
/** | |||
* Retourne le résumé du panier au format HTML. | |||
*/ | |||
public function getCartSummary(Order $order, $htmlFormat = true): string | |||
{ | |||
if (!isset($order->productOrder)) { | |||
$order->productOrder = $this->productOrderRepository->getByOrder($order); | |||
} | |||
$html = ''; | |||
$i = 0; | |||
$count = count($order->productOrder); | |||
foreach ($order->productOrder as $p) { | |||
if (isset($p->product)) { | |||
$html .= Html::encode($p->product->name) . ' (' . $p->quantity . ' ' . Product::strUnit( | |||
$p->unit, | |||
'wording_short', | |||
true | |||
) . ')'; | |||
if (++$i != $count) { | |||
if ($htmlFormat) { | |||
$html .= '<br />'; | |||
} else { | |||
$html .= "\n"; | |||
} | |||
} | |||
} | |||
} | |||
return $html; | |||
} | |||
/** | |||
* Retourne le résumé du paiement (montant, statut). | |||
*/ | |||
public function getAmountSummary(Order $order): string | |||
{ | |||
$html = ''; | |||
$creditActive = $this->producerRepository->getConfig('credit'); | |||
$html .= $this->orderSolver->getAmountWithTax($order, Order::AMOUNT_TOTAL, true); | |||
if ($creditActive) { | |||
$html .= '<br />'; | |||
if ($order->paid_amount) { | |||
if ($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_PAID) { | |||
$html .= '<span class="label label-success">Payée</span>'; | |||
} elseif ($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_UNPAID) { | |||
$html .= '<span class="label label-danger">Non payée</span><br /> | |||
Reste <strong>' . $this->orderSolver->getAmount( | |||
$order, | |||
Order::AMOUNT_REMAINING, | |||
true | |||
) . '</strong> à payer'; | |||
} elseif ($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_SURPLUS) { | |||
$html .= '<span class="label label-success">Payée</span>'; | |||
} | |||
} else { | |||
$html .= '<span class="label label-default">Non réglé</span>'; | |||
} | |||
} | |||
return $html; | |||
} | |||
/** | |||
* Retourne l'état de la commande (livrée, modifiable ou en préparation. | |||
*/ | |||
public function getState(Order $order): string | |||
{ | |||
$orderDate = strtotime($order->distribution->date); | |||
$today = strtotime(date('Y-m-d')); | |||
$todayHour = date('G'); | |||
$dayDistribution = strtolower(date('l', strtotime($order->distribution->date))); | |||
$orderDelay = $this->producerRepository->getConfig( | |||
'order_delay', | |||
$order->distribution->id_producer | |||
); | |||
$orderDelaySpecific = $this->producerRepository->getConfig( | |||
'order_delay_' . $dayDistribution, | |||
$order->distribution->id_producer | |||
); | |||
if ($orderDelaySpecific) { | |||
$orderDelay = $orderDelaySpecific; | |||
} | |||
$orderDeadline = $this->producerRepository->getConfig( | |||
'order_deadline', | |||
$order->distribution->id_producer | |||
); | |||
$orderDeadlineSpecific = $this->producerRepository->getConfig( | |||
'order_deadline_' . $dayDistribution, | |||
$order->distribution->id_producer | |||
); | |||
if ($orderDeadlineSpecific) { | |||
$orderDeadline = $orderDeadlineSpecific; | |||
} | |||
$nbDays = (int) round((($orderDate - $today) / (24 * 60 * 60))); | |||
if ($nbDays <= 0) { | |||
return Order::STATE_DELIVERED; | |||
} elseif ($nbDays >= $orderDelay && | |||
($nbDays != $orderDelay || | |||
($nbDays == $orderDelay && $todayHour < $orderDeadline))) { | |||
return Order::STATE_OPEN; | |||
} | |||
return Order::STATE_PREPARATION; | |||
} | |||
public function getOneLastOfYear(Producer $producer) | |||
{ | |||
return Order::find()->innerJoinWith('distribution', true) | |||
->where(['>=', 'distribution.date', date('Y') . '-01-01']) | |||
->andWhere([ | |||
'distribution.id_producer' => $producer->id | |||
]) | |||
->andWhere(['not', ['order.reference' => null]]) | |||
->orderBy('order.reference DESC') | |||
->one(); | |||
} | |||
} |
@@ -2,10 +2,368 @@ | |||
namespace common\logic\Order\Order; | |||
use common\helpers\GlobalParam; | |||
use common\helpers\Price; | |||
use common\logic\BaseService; | |||
use common\logic\Document\Document\Document; | |||
use common\logic\Document\Document\DocumentSolver; | |||
use common\logic\Order\ProductOrder\ProductOrder; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\Product\Product\Product; | |||
use common\logic\SolverInterface; | |||
use yii\helpers\Html; | |||
class OrderSolver extends BaseService implements SolverInterface | |||
{ | |||
protected DocumentSolver $documentSolver; | |||
public function __construct() | |||
{ | |||
$this->documentSolver = $this->loadService(DocumentSolver::class); | |||
} | |||
public function getFieldNameAmount($typeTotal = Order::AMOUNT_TOTAL, $typeField = ''): string | |||
{ | |||
$fieldName = 'amount'; | |||
if ($typeTotal == Order::INVOICE_AMOUNT_TOTAL) { | |||
$fieldName = 'invoice_amount'; | |||
} | |||
if ($typeField == 'vat') { | |||
$fieldName = $fieldName . '_vat'; | |||
} elseif ($typeField == 'with_tax') { | |||
$fieldName = $fieldName . '_with_tax'; | |||
} | |||
return $fieldName; | |||
} | |||
public function getTotalVat(Order $order, $typeTotal = Order::AMOUNT_TOTAL): float | |||
{ | |||
$fieldName = $this->getFieldNameAmount($typeTotal, 'vat'); | |||
$totalVat = 0; | |||
foreach ($order->$fieldName as $vat) { | |||
$totalVat += $vat; | |||
} | |||
return $totalVat; | |||
} | |||
/** | |||
* Retourne le statut de paiement de la commande (payée, surplus, ou impayée). | |||
*/ | |||
public function getPaymentStatus(Order $order): ?string | |||
{ | |||
// payé | |||
if ($this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) < 0.01 && | |||
$this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) > -0.01) { | |||
return Order::PAYMENT_PAID; | |||
} // à rembourser | |||
elseif ($this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) <= -0.01) { | |||
return Order::PAYMENT_SURPLUS; | |||
} // reste à payer | |||
elseif ($this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) >= 0.01) { | |||
return Order::PAYMENT_UNPAID; | |||
} | |||
return null; | |||
} | |||
/** | |||
* Retourne le résumé du point de vente lié à la commande au format HTML. | |||
*/ | |||
public function getPointSaleSummary(Order $order): string | |||
{ | |||
$html = ''; | |||
if (isset($order->pointSale)) { | |||
$html .= '<span class="name-point-sale">' . | |||
Html::encode($order->pointSale->name) . | |||
'</span>' . | |||
'<br /><span class="locality">' | |||
. Html::encode($order->pointSale->locality) | |||
. '</span>'; | |||
if (strlen($order->comment_point_sale)) { | |||
$html .= '<div class="comment"><span>' | |||
. Html::encode($order->comment_point_sale) | |||
. '</span></div>'; | |||
} | |||
} else { | |||
$html .= 'Point de vente supprimé'; | |||
} | |||
return $html; | |||
} | |||
/** | |||
* Retourne une chaine de caractère décrivant l'utilisateur lié à la commande. | |||
*/ | |||
public function getStrUser(Order $order): string | |||
{ | |||
if (isset($order->user)) { | |||
if (isset($order->user->name_legal_person) && strlen($order->user->name_legal_person)) { | |||
return Html::encode($order->user->name_legal_person); | |||
} else { | |||
$strUser = $order->user->lastname; | |||
if ($order->user->lastname && $order->user->name) { | |||
$strUser .= ' ' . $order->user->name; | |||
} | |||
return Html::encode($strUser); | |||
} | |||
} elseif (strlen($order->username)) { | |||
return Html::encode($order->username); | |||
} else { | |||
return 'Client introuvable'; | |||
} | |||
} | |||
public function isLinkedToValidDocument(Order $order): bool | |||
{ | |||
return ($order->deliveryNote && $this->documentSolver->isStatusValid($order->deliveryNote)) | |||
|| ($order->quotation && $this->documentSolver->isStatusValid($order->quotation)) | |||
|| ($order->invoice && $this->documentSolver->isStatusValid($order->invoice)); | |||
} | |||
public function getCommentReport(Order $order): string | |||
{ | |||
$comment = ''; | |||
$hasComment = false; | |||
if ($order->comment && strlen($order->comment) > 0) { | |||
$hasComment = true; | |||
$comment .= $order->comment; | |||
} | |||
if ($order->delivery_home && $order->delivery_address && strlen($order->delivery_address) > 0) { | |||
if ($hasComment) { | |||
$comment .= '<br /><br />'; | |||
} | |||
$comment .= '<strong>Livraison à domicile :</strong><br />'; | |||
$comment .= nl2br($order->delivery_address); | |||
} | |||
return $comment; | |||
} | |||
public function getUsername(Order $order): string | |||
{ | |||
$username = ''; | |||
if ($order->user) { | |||
$username = $order->user->getUsername(); | |||
} | |||
if (strlen($order->username)) { | |||
$username = $order->username; | |||
} | |||
return $username; | |||
} | |||
/** | |||
* Retourne un bloc html présentant une date. | |||
*/ | |||
public function getBlockDate(Order $order): string | |||
{ | |||
return '<div class="block-date"> | |||
<div class="day">' . strftime('%A', strtotime($order->distribution->date)) . '</div> | |||
<div class="num">' . date('d', strtotime($order->distribution->date)) . '</div> | |||
<div class="month">' . strftime('%B', strtotime($order->distribution->date)) . '</div> | |||
</div>'; | |||
} | |||
/** | |||
* Retourne le nombre de produits commandés. | |||
*/ | |||
public function countProducts(Order $order) | |||
{ | |||
if ($order->productOrder && is_array($order->productOrder)) { | |||
return count($order->productOrder); | |||
} | |||
return 0; | |||
} | |||
public function getProductQuantityPieces(Product $product, array $orders): int | |||
{ | |||
$quantity = 0; | |||
if (isset($orders) && is_array($orders) && count($orders)) { | |||
foreach ($orders as $c) { | |||
if (is_null($c->date_delete)) { | |||
foreach ($c->productOrder as $po) { | |||
if ($po->id_product == $product->id) { | |||
if ($po->unit == 'piece') { | |||
$quantity += $po->quantity; | |||
} else { | |||
if (isset($po->product) && $po->product->weight > 0) { | |||
$quantity += ($po->quantity * Product::$unitsArray[$po->unit]['coefficient']) / $po->product->weight; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return $quantity; | |||
} | |||
/** | |||
* Retourne la quantité d'un produit donné de plusieurs commandes. | |||
*/ | |||
public function getProductQuantity(Product $product, array $orders, $ignoreCancel = false, $unit = null): int | |||
{ | |||
$quantity = 0; | |||
if (isset($orders) && is_array($orders) && count($orders)) { | |||
foreach ($orders as $c) { | |||
if (is_null($c->date_delete) || $ignoreCancel) { | |||
foreach ($c->productOrder as $po) { | |||
if ($po->id_product == $product->id && | |||
((is_null($unit) && $po->product->unit == $po->unit) || (!is_null($unit) && strlen( | |||
$unit | |||
) && $po->unit == $unit))) { | |||
$quantity += $po->quantity; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return $quantity; | |||
} | |||
/** | |||
* Retourne une classe identifiant l'historique de la commande (ajoutée, | |||
* modifiée, supprimée). | |||
*/ | |||
public function getClassHistory(Order $order): string | |||
{ | |||
if (!is_null($order->date_delete)) { | |||
return 'commande-delete'; | |||
} | |||
if (!is_null($order->date_update)) { | |||
return 'commande-update'; | |||
} | |||
return 'commande-create'; | |||
} | |||
/** | |||
* Retourne l'historique de la commande (ajoutée, modifiée, supprimée) au format HTML. | |||
*/ | |||
public function getStrHistory(Order $order): string | |||
{ | |||
$arr = [ | |||
'class' => 'create', | |||
'glyphicon' => 'plus', | |||
'str' => 'Ajoutée', | |||
'date' => $order->date | |||
]; | |||
if (!is_null($order->date_update)) { | |||
$arr = [ | |||
'class' => 'update', | |||
'glyphicon' => 'pencil', | |||
'str' => 'Modifiée', | |||
'date' => $order->date_update | |||
]; | |||
} | |||
if (!is_null($order->date_delete)) { | |||
$arr = [ | |||
'class' => 'delete', | |||
'glyphicon' => 'remove', | |||
'str' => 'Annulée', | |||
'date' => $order->date_delete | |||
]; | |||
} | |||
$html = '<div class="small"><span class="' . $arr['class'] . '">' | |||
. '<span class="glyphicon glyphicon-' . $arr['glyphicon'] . '"></span> ' | |||
. $arr['str'] . '</span> le <strong>' | |||
. date('d/m/Y à G\hi', strtotime($arr['date'])) . '</strong></div>'; | |||
return $html; | |||
} | |||
/** | |||
* Retourne l'origine de la commande (client, automatique ou admin) sous forme texte ou HTML. | |||
*/ | |||
public function getStrOrigin(Order $order, $withLabel = false): string | |||
{ | |||
$classLabel = ''; | |||
$str = ''; | |||
if ($order->origin == Order::ORIGIN_USER) { | |||
$classLabel = 'success'; | |||
$str = 'Client'; | |||
} elseif ($order->origin == Order::ORIGIN_AUTO) { | |||
$classLabel = 'default'; | |||
$str = 'Auto'; | |||
} elseif ($order->origin == Order::ORIGIN_ADMIN) { | |||
$classLabel = 'warning'; | |||
$str = 'Vous'; | |||
} | |||
if ($withLabel) { | |||
return '<span class="label label-' . $classLabel . '">' | |||
. $str . '</span>'; | |||
} else { | |||
return $str; | |||
} | |||
} | |||
/** | |||
* Retourne le montant de la commande (total, payé, restant, ou en surplus). | |||
*/ | |||
public function getAmount(Order $order, string $type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
$amount = $order->amount; | |||
if ($type == Order::INVOICE_AMOUNT_TOTAL && $order->invoice_amount) { | |||
$amount = $order->invoice_amount; | |||
} | |||
return $this->_getAmountGeneric($order, $type, $amount, $format); | |||
} | |||
public function getAmountWithTax(Order $order, string $type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
$amount = $order->amount + $this->getTotalVat($order, $type); | |||
if ($type == Order::INVOICE_AMOUNT_TOTAL && $order->invoice_amount) { | |||
$amount = $order->invoice_amount + $this->getTotalVat($order, $type); | |||
} | |||
return $this->_getAmountGeneric($order, $type, $amount, $format); | |||
} | |||
protected function _getAmountGeneric(Order $order, string $type, float $amountOrder, bool $format) | |||
{ | |||
switch ($type) { | |||
case Order::AMOUNT_TOTAL : | |||
case Order::INVOICE_AMOUNT_TOTAL : | |||
$amount = $amountOrder; | |||
break; | |||
case Order::AMOUNT_PAID : | |||
$amount = $order->paid_amount; | |||
break; | |||
case Order::AMOUNT_REMAINING : | |||
$amount = $this->getAmountWithTax($order, Order::AMOUNT_TOTAL) | |||
- $this->getAmountWithTax($order,Order::AMOUNT_PAID); | |||
break; | |||
case Order::AMOUNT_SURPLUS : | |||
$amount = $this->getAmountWithTax($order,Order::AMOUNT_PAID) | |||
- $this->getAmountWithTax($order,Order::AMOUNT_TOTAL); | |||
break; | |||
} | |||
if ($format) { | |||
return Price::format($amount); | |||
} else { | |||
return $amount; | |||
} | |||
} | |||
} |
@@ -3,78 +3,60 @@ | |||
namespace common\logic\Order\OrderStatusHistory; | |||
use common\components\ActiveRecordCommon; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\User\User\User; | |||
/** | |||
* This is the model class for table "order_order_status". | |||
* | |||
* @property integer $id | |||
* @property integer $id_order | |||
* @property integer $id_order_status | |||
* @property string $date | |||
* This is the model class for table "order_status_history". | |||
*/ | |||
class OrderStatusHistory extends ActiveRecordCommon | |||
{ | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'order_status_history'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['id_order', 'status', 'id_user', 'date', 'origin'], 'required'], | |||
[['id_order', 'id_user',], 'integer'], | |||
[['date'], 'safe'], | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'id_order' => 'Commande', | |||
'id_user' => 'Utilisateur', | |||
'status' => 'Statut', | |||
'origin' => 'Origine', | |||
'date' => 'Date', | |||
]; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrder() | |||
{ | |||
return $this->hasOne( User::className(), ['id' => 'id_order']); | |||
} | |||
public function getUser() | |||
{ | |||
return $this->hasOne( User::className(), ['id' => 'id_user']); | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => ['order', 'orderStatus'], | |||
'orderby' => 'date ASC', | |||
'attribute_id_producer' => '' | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'order_status_history'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['id_order', 'status', 'id_user', 'date', 'origin'], 'required'], | |||
[['id_order', 'id_user',], 'integer'], | |||
[['date'], 'safe'], | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'id_order' => 'Commande', | |||
'id_user' => 'Utilisateur', | |||
'status' => 'Statut', | |||
'origin' => 'Origine', | |||
'date' => 'Date', | |||
]; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getOrder() | |||
{ | |||
return $this->hasOne(Order::class, ['id' => 'id_order']); | |||
} | |||
public function getUser() | |||
{ | |||
return $this->hasOne(User::class, ['id' => 'id_user']); | |||
} | |||
} |
@@ -4,13 +4,37 @@ namespace common\logic\Order\OrderStatusHistory; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\User\User\User; | |||
use common\logic\User\User\UserSolver; | |||
class OrderStatusHistoryBuilder extends BaseService implements BuilderInterface | |||
{ | |||
public function instanciate(): OrderStatusHistory | |||
protected UserSolver $userSolver; | |||
public function __construct() | |||
{ | |||
$this->userSolver = $this->loadService(UserSolver::class); | |||
} | |||
public function instanciate(Order $order, User $user, string $status, string $origin): OrderStatusHistory | |||
{ | |||
$orderStatusHistory = new OrderStatusHistory(); | |||
$orderStatusHistory->id_order = $order->id; | |||
$orderStatusHistory->populateRelation('order', $order); | |||
$orderStatusHistory->id_user = $user->id; | |||
$orderStatusHistory->populateRelation('user', $user); | |||
$orderStatusHistory->status = $status; | |||
$orderStatusHistory->origin = $origin; | |||
$orderStatusHistory->date = date('Y-m-d H:i:s'); | |||
return $orderStatusHistory; | |||
} | |||
public function create(Order $order, User $user, string $status, string $origin): OrderStatusHistory | |||
{ | |||
$orderStatusHistory = $this->instanciate($order, $user, $status, $origin); | |||
$orderStatusHistory->save(); | |||
} | |||
} |
@@ -7,5 +7,13 @@ use common\logic\RepositoryInterface; | |||
class OrderStatusHistoryRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => ['order', 'orderStatus'], | |||
'orderby' => 'date ASC', | |||
'attribute_id_producer' => '' | |||
]; | |||
} | |||
} |
@@ -41,120 +41,84 @@ namespace common\logic\Order\ProductOrder; | |||
use common\helpers\GlobalParam; | |||
use common\helpers\Price; | |||
use common\components\ActiveRecordCommon; | |||
use common\logic\Config\TaxRate\TaxRate; | |||
use common\logic\Product\Product\Product; | |||
/** | |||
* This is the model class for table "product_order". | |||
* | |||
* @property integer $id | |||
* @property integer $id_order | |||
* @property integer $id_product | |||
* @property double $quantity | |||
* @property string $unit | |||
*/ | |||
class ProductOrder extends ActiveRecordCommon | |||
{ | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'product_order'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getProduct() | |||
{ | |||
return $this->hasOne( Product::className(), ['id' => 'id_product']); | |||
} | |||
public function getTaxRate() | |||
{ | |||
return $this->hasOne(TaxRate::className(), ['id' => 'id_tax_rate']); | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['id_order', 'id_product', 'quantity'], 'required'], | |||
[['id_order', 'id_product', 'id_tax_rate'], 'integer'], | |||
[['unit'], 'string', 'max' => 255], | |||
[['quantity'], 'number', 'min' => 0], | |||
[['price', 'invoice_price'], 'double'], | |||
[['description'], 'safe'] | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'id_order' => 'Commande', | |||
'id_product' => 'Product', | |||
'quantity' => 'Quantité', | |||
'unit' => 'Unité', | |||
'id_tax_rate' => 'Taxe', | |||
'description' => 'Description', | |||
'price' => 'Prix', | |||
'invoice_price' => 'Prix facturé', | |||
]; | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => ['taxRate'], | |||
'join_with' => [], | |||
'orderby' => '', | |||
'attribute_id_producer' => '' | |||
]; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'product_order'; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getProduct() | |||
{ | |||
return $this->hasOne(Product::class, ['id' => 'id_product']); | |||
} | |||
public function getTaxRate() | |||
{ | |||
return $this->hasOne(TaxRate::class, ['id' => 'id_tax_rate']); | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['id_order', 'id_product', 'quantity'], 'required'], | |||
[['id_order', 'id_product', 'id_tax_rate'], 'integer'], | |||
[['unit'], 'string', 'max' => 255], | |||
[['quantity'], 'number', 'min' => 0], | |||
[['price', 'invoice_price'], 'double'], | |||
[['description'], 'safe'] | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'id_order' => 'Commande', | |||
'id_product' => 'Product', | |||
'quantity' => 'Quantité', | |||
'unit' => 'Unité', | |||
'id_tax_rate' => 'Taxe', | |||
'description' => 'Description', | |||
'price' => 'Prix', | |||
'invoice_price' => 'Prix facturé', | |||
]; | |||
} | |||
public function afterFind() | |||
{ | |||
if ($this->taxRate == null) { | |||
$this->populateRelation('taxRate', GlobalParam::getCurrentProducer()->taxRate); | |||
} | |||
public function afterFind() { | |||
if ($this->taxRate == null) { | |||
$this->populateRelation('taxRate', GlobalParam::getCurrentProducer()->taxRate); | |||
} | |||
parent::afterFind(); | |||
} | |||
public function getPrice() | |||
{ | |||
return $this->price ; | |||
} | |||
public function getInvoicePrice() { | |||
return $this->invoice_price ; | |||
} | |||
/** | |||
* Retourne le prix du produit avec taxe | |||
*/ | |||
public function getPriceWithTax() | |||
{ | |||
return Price::getPriceWithTax($this->price, $this->taxRate->value); | |||
} | |||
public function getPriceByTypeTotal($typeTotal = Order::AMOUNT_TOTAL) | |||
{ | |||
if($typeTotal == Order::INVOICE_AMOUNT_TOTAL && $this->invoice_price) { | |||
return $this->invoice_price; | |||
} | |||
return $this->price; | |||
} | |||
parent::afterFind(); | |||
} | |||
public function getPrice() | |||
{ | |||
return $this->price; | |||
} | |||
public function getInvoicePrice() | |||
{ | |||
return $this->invoice_price; | |||
} | |||
} |
@@ -4,6 +4,7 @@ namespace common\logic\Order\ProductOrder; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\PointSale\PointSale\PointSale; | |||
use common\logic\Product\Product\ProductSolver; | |||
use common\logic\User\User\User; | |||
@@ -45,4 +46,20 @@ class ProductOrderBuilder extends BaseService implements BuilderInterface | |||
return $productOrder; | |||
} | |||
public function updateInvoicePrice(ProductOrder $productOrder, array $params = []): void | |||
{ | |||
$productOrder->invoice_price = $this->productSolver->getPrice($productOrder->product, [ | |||
'user' => isset($params['user']) ?? null, | |||
'user_producer' => isset($params['user_producer']) ?? null, | |||
'point_sale' => isset($params['point_sale']) ?? null, | |||
'quantity' => $productOrder->quantity | |||
]); | |||
$productOrder->save(); | |||
} | |||
public function deleteByOrder(Order $order): void | |||
{ | |||
ProductOrder::deleteAll(['id_order' => $order->id]); | |||
} | |||
} |
@@ -3,9 +3,24 @@ | |||
namespace common\logic\PointSale\PointSale; | |||
use common\logic\BaseService; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\Order\ProductOrder\ProductOrder; | |||
use common\logic\RepositoryInterface; | |||
class ProductOrderRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => ['taxRate'], | |||
'join_with' => [], | |||
'orderby' => '', | |||
'attribute_id_producer' => '' | |||
]; | |||
} | |||
public function getByOrder(Order $order) | |||
{ | |||
return ProductOrder::find()->where(['id_order' => $order->id])->all() | |||
} | |||
} |
@@ -2,10 +2,27 @@ | |||
namespace common\logic\Order\ProductOrder; | |||
use common\helpers\Price; | |||
use common\logic\BaseService; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\SolverInterface; | |||
class ProductOrderSolver extends BaseService implements SolverInterface | |||
{ | |||
/** | |||
* Retourne le prix du produit avec taxe | |||
*/ | |||
public function getPriceWithTax(ProductOrder $productOrder): float | |||
{ | |||
return Price::getPriceWithTax($productOrder->price, $productOrder->taxRate->value); | |||
} | |||
public function getPriceByTypeTotal(ProductOrder $productOrder, string $typeTotal = Order::AMOUNT_TOTAL): float | |||
{ | |||
if ($typeTotal == Order::INVOICE_AMOUNT_TOTAL && $productOrder->invoice_price) { | |||
return $productOrder->invoice_price; | |||
} | |||
return $productOrder->price; | |||
} | |||
} |
@@ -39,362 +39,305 @@ | |||
namespace common\logic\PointSale\PointSale; | |||
use common\helpers\GlobalParam; | |||
use common\logic\Distribution\PointSaleDistribution\PointSaleDistribution; | |||
use common\logic\PointSale\UserPointSale\UserPointSale; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\User\User\User; | |||
use yii\helpers\Html; | |||
use common\components\ActiveRecordCommon; | |||
/** | |||
* This is the model class for table "point_vente". | |||
* | |||
* @property integer $id | |||
* @property string $name | |||
* @property string $address | |||
* @property integer $id_producer | |||
* @property integer $default | |||
* This is the model class for table "point_sale". | |||
*/ | |||
class PointSale extends ActiveRecordCommon | |||
{ | |||
var $orders = []; | |||
var $revenues = 0; | |||
var $revenues_with_tax = 0; | |||
var $data_select_orders; | |||
var $data_options_orders; | |||
var $users = []; | |||
var $users_comment = []; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'point_sale'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['name'], 'required'], | |||
[['restricted_access'], 'boolean'], | |||
[['name', 'code'], 'string', 'max' => 255], | |||
[['address', 'locality', 'infos_monday', 'infos_tuesday', | |||
'infos_wednesday', 'infos_thursday', 'infos_friday', | |||
'infos_saturday', 'infos_sunday', 'credit_functioning', 'bread_box_code'], 'string'], | |||
[['point_production', 'credit', 'delivery_monday', 'delivery_tuesday', | |||
'delivery_wednesday', 'delivery_thursday', 'delivery_friday', | |||
'delivery_saturday', 'delivery_sunday', 'default', 'is_bread_box'], 'boolean'], | |||
['point_production', 'default', 'value' => 0], | |||
[['id_producer', 'id_user', 'maximum_number_orders', 'status'], 'integer'], | |||
['id_producer', 'required'], | |||
[['users', 'users_comment', 'code'], 'safe'], | |||
[['product_price_percent'], 'double'], | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'name' => 'Nom', | |||
'address' => 'Adresse', | |||
'locality' => 'Localité', | |||
'point_production' => 'Point de production', | |||
'infos_monday' => 'Lundi', | |||
'infos_tuesday' => 'Mardi', | |||
'infos_wednesday' => 'Mercredi', | |||
'infos_thursday' => 'Jeudi', | |||
'infos_friday' => 'Vendredi', | |||
'infos_saturday' => 'Samedi', | |||
'infos_sunday' => 'Dimanche', | |||
'restricted_access' => 'Accès restreint', | |||
'credit' => 'Activer le Crédit', | |||
'delivery_monday' => 'Lundi', | |||
'delivery_tuesday' => 'Mardi', | |||
'delivery_wednesday' => 'Mercredi', | |||
'delivery_thursday' => 'Jeudi', | |||
'delivery_friday' => 'Vendredi', | |||
'delivery_saturday' => 'Samedi', | |||
'delivery_sunday' => 'Dimanche', | |||
'code' => 'Code', | |||
'credit_functioning' => 'Utilisation du Crédit par l\'utilisateur', | |||
'default' => 'Point de vente par défaut', | |||
'id_user' => 'Contact', | |||
'product_price_percent' => 'Prix produits : pourcentage', | |||
'maximum_number_orders' => 'Nombre maximum de commandes', | |||
'is_bread_box' => 'Boîte à pain', | |||
'bread_box_code' => 'Code boîte à pain', | |||
'status' => 'Statut' | |||
]; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getUserPointSale() | |||
{ | |||
return $this->hasMany( | |||
UserPointSale::className(), | |||
['id_point_sale' => 'id'] | |||
); | |||
} | |||
public function getPointSaleDistribution() | |||
{ | |||
return $this->hasMany( | |||
PointSaleDistributionModel::className(), | |||
['id_point_sale' => 'id'] | |||
); | |||
} | |||
public function getUser() | |||
{ | |||
return $this->hasOne( | |||
User::className(), | |||
['id' => 'id_user'] | |||
) ; | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => [], | |||
'orderby' => 'is_bread_box ASC, name ASC', | |||
'attribute_id_producer' => 'point_sale.id_producer' | |||
]; | |||
var $orders = []; | |||
var $revenues = 0; | |||
var $revenues_with_tax = 0; | |||
var $data_select_orders; | |||
var $data_options_orders; | |||
var $users = []; | |||
var $users_comment = []; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'point_sale'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['name'], 'required'], | |||
[['restricted_access'], 'boolean'], | |||
[['name', 'code'], 'string', 'max' => 255], | |||
[['address', 'locality', 'infos_monday', 'infos_tuesday', | |||
'infos_wednesday', 'infos_thursday', 'infos_friday', | |||
'infos_saturday', 'infos_sunday', 'credit_functioning', 'bread_box_code'], 'string'], | |||
[['point_production', 'credit', 'delivery_monday', 'delivery_tuesday', | |||
'delivery_wednesday', 'delivery_thursday', 'delivery_friday', | |||
'delivery_saturday', 'delivery_sunday', 'default', 'is_bread_box'], 'boolean'], | |||
['point_production', 'default', 'value' => 0], | |||
[['id_producer', 'id_user', 'maximum_number_orders', 'status'], 'integer'], | |||
['id_producer', 'required'], | |||
[['users', 'users_comment', 'code'], 'safe'], | |||
[['product_price_percent'], 'double'], | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'name' => 'Nom', | |||
'address' => 'Adresse', | |||
'locality' => 'Localité', | |||
'point_production' => 'Point de production', | |||
'infos_monday' => 'Lundi', | |||
'infos_tuesday' => 'Mardi', | |||
'infos_wednesday' => 'Mercredi', | |||
'infos_thursday' => 'Jeudi', | |||
'infos_friday' => 'Vendredi', | |||
'infos_saturday' => 'Samedi', | |||
'infos_sunday' => 'Dimanche', | |||
'restricted_access' => 'Accès restreint', | |||
'credit' => 'Activer le Crédit', | |||
'delivery_monday' => 'Lundi', | |||
'delivery_tuesday' => 'Mardi', | |||
'delivery_wednesday' => 'Mercredi', | |||
'delivery_thursday' => 'Jeudi', | |||
'delivery_friday' => 'Vendredi', | |||
'delivery_saturday' => 'Samedi', | |||
'delivery_sunday' => 'Dimanche', | |||
'code' => 'Code', | |||
'credit_functioning' => 'Utilisation du Crédit par l\'utilisateur', | |||
'default' => 'Point de vente par défaut', | |||
'id_user' => 'Contact', | |||
'product_price_percent' => 'Prix produits : pourcentage', | |||
'maximum_number_orders' => 'Nombre maximum de commandes', | |||
'is_bread_box' => 'Boîte à pain', | |||
'bread_box_code' => 'Code boîte à pain', | |||
'status' => 'Statut' | |||
]; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getUserPointSale() | |||
{ | |||
return $this->hasMany( | |||
UserPointSale::class, | |||
['id_point_sale' => 'id'] | |||
); | |||
} | |||
public function getPointSaleDistribution() | |||
{ | |||
return $this->hasMany( | |||
PointSaleDistribution::class, | |||
['id_point_sale' => 'id'] | |||
); | |||
} | |||
public function getUser() | |||
{ | |||
return $this->hasOne( | |||
User::class, | |||
['id' => 'id_user'] | |||
); | |||
} | |||
/** | |||
* Enregistre le point de vente. | |||
*/ | |||
public function save(bool $runValidation = true, array $attributeNames = NULL) | |||
{ | |||
$this->id_producer = GlobalParam::getCurrentProducerId(); | |||
return parent::save($runValidation, $attributeNames); | |||
} | |||
/** | |||
* Traite la mise à jour de l'attribut 'point_production'. | |||
*/ | |||
public function processPointProduction() | |||
{ | |||
if ($this->point_production) { | |||
PointSale::updateAll( | |||
['point_production' => 0], | |||
['id_producer' => $this->id_producer] | |||
); | |||
$this->point_production = 1; | |||
$this->save(); | |||
} | |||
/** | |||
* Initialise les commandes liées au point de vente. | |||
* | |||
* @param array $ordersArray | |||
*/ | |||
public function initOrders($ordersArray) | |||
{ | |||
$this->orders = []; | |||
$this->revenues = 0; | |||
$this->revenues_with_tax = 0; | |||
if ($ordersArray) { | |||
foreach ($ordersArray as $order) { | |||
if ($this->id == $order->id_point_sale) { | |||
$this->orders[] = $order; | |||
if (is_null($order->date_delete)) { | |||
$this->revenues += (float)$order->amount; | |||
$this->revenues_with_tax += (float)$order->amount_with_tax; | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Traite les accès restreints d'un point de vente. | |||
*/ | |||
public function processRestrictedAccess() | |||
{ | |||
UserPointSale::deleteAll(['id_point_sale' => $this->id]); | |||
if (is_array($this->users) && count($this->users)) { | |||
foreach ($this->users as $key => $val) { | |||
$user = User::findOne($val); | |||
if ($user) { | |||
$userPointSale = new UserPointSale; | |||
$userPointSale->id_user = $val; | |||
$userPointSale->id_point_sale = $this->id; | |||
if (isset($this->users_comment[$val]) && strlen($this->users_comment[$val])) { | |||
$userPointSale->comment = $this->users_comment[$val]; | |||
} | |||
$userPointSale->save(); | |||
} | |||
} | |||
} | |||
/** | |||
* Retourne les commandes liées à ce point de vente. | |||
* | |||
* @return array | |||
*/ | |||
public function getOrders() | |||
{ | |||
return $this->orders; | |||
} | |||
/** | |||
* Enregistre le point de vente. | |||
* | |||
* @param boolean $runValidation | |||
* @param array $attributeNames | |||
* @return type | |||
*/ | |||
public function save($runValidation = true, $attributeNames = NULL) | |||
{ | |||
$this->id_producer = GlobalParam::getCurrentProducerId(); | |||
return parent::save($runValidation, $attributeNames); | |||
} | |||
/** | |||
* Traite la mise à jour de l'attribut 'point_production'. | |||
*/ | |||
public function processPointProduction() | |||
{ | |||
if ($this->point_production) { | |||
PointSale::updateAll( | |||
['point_production' => 0], | |||
['id_producer' => $this->id_producer] | |||
); | |||
$this->point_production = 1; | |||
$this->save(); | |||
} | |||
/** | |||
* Retourne le commentaire de l'utilisateur courant lié au point de vente. | |||
* | |||
* @return string|null | |||
*/ | |||
public function getComment() | |||
{ | |||
if (isset($this->userPointSale)) { | |||
foreach ($this->userPointSale as $userPointSale) { | |||
if ($userPointSale->id_user == User::getCurrentId()) { | |||
return $userPointSale->comment; | |||
} | |||
} | |||
} | |||
/** | |||
* Traite les accès restreints d'un point de vente. | |||
*/ | |||
public function processRestrictedAccess() | |||
{ | |||
UserPointSale::deleteAll(['id_point_sale' => $this->id]); | |||
if (is_array($this->users) && count($this->users)) { | |||
foreach ($this->users as $key => $val) { | |||
$user = User::findOne($val); | |||
if ($user) { | |||
$userPointSale = new UserPointSale; | |||
$userPointSale->id_user = $val; | |||
$userPointSale->id_point_sale = $this->id; | |||
if (isset($this->users_comment[$val]) && strlen($this->users_comment[$val])) { | |||
$userPointSale->comment = $this->users_comment[$val]; | |||
} | |||
$userPointSale->save(); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Retourne le commentaire de l'utilisateur courant lié au point de vente. | |||
* | |||
* @return string|null | |||
*/ | |||
public function getComment() | |||
{ | |||
if (isset($this->userPointSale)) { | |||
foreach ($this->userPointSale as $userPointSale) { | |||
if ($userPointSale->id_user == User::getCurrentId()) { | |||
return $userPointSale->comment; | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Retourne le nombre de points de vente pour l'établissement courant. | |||
* | |||
* @return integer | |||
*/ | |||
public static function count() | |||
{ | |||
return self::searchCount(['id_producer' => GlobalParam::getCurrentProducerId()]); | |||
} | |||
/** | |||
* Vérifie le code d'accès à un point de vente. | |||
* | |||
* @param string $code | |||
* @return boolean | |||
*/ | |||
public function validateCode($code) | |||
{ | |||
if (strlen($this->code)) { | |||
if (trim(strtolower($code)) == trim(strtolower($this->code))) { | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Retourne le nombre de points de vente pour l'établissement courant. | |||
* | |||
* @return integer | |||
*/ | |||
public static function count() | |||
{ | |||
return self::searchCount(['id_producer' => GlobalParam::getCurrentProducerId()]); | |||
} | |||
/** | |||
* Vérifie le code d'accès à un point de vente. | |||
* | |||
* @param string $code | |||
* @return boolean | |||
*/ | |||
public function validateCode($code) | |||
{ | |||
if (strlen($this->code)) { | |||
if (trim(strtolower($code)) == trim(strtolower($this->code))) { | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
/** | |||
* Retourne les jours de livraison du point de vente sous forme d'une chaine | |||
* de caractères. | |||
* | |||
* @return string | |||
*/ | |||
public function getStrDeliveryDays() | |||
{ | |||
$str = ''; | |||
if ($this->delivery_monday) $str .= 'lundi, '; | |||
if ($this->delivery_tuesday) $str .= 'mardi, '; | |||
if ($this->delivery_wednesday) $str .= 'mercredi, '; | |||
if ($this->delivery_thursday) $str .= 'jeudi, '; | |||
if ($this->delivery_friday) $str .= 'vendredi, '; | |||
if ($this->delivery_saturday) $str .= 'samedi, '; | |||
if ($this->delivery_sunday) $str .= 'dimanche, '; | |||
if (strlen($str)) { | |||
return substr($str, 0, strlen($str) - 2); | |||
} else { | |||
return ''; | |||
} | |||
return true; | |||
} | |||
/** | |||
* Retourne les jours de livraison du point de vente sous forme d'une chaine | |||
* de caractères. | |||
* | |||
* @return string | |||
*/ | |||
public function getStrDeliveryDays() | |||
{ | |||
$str = ''; | |||
if ($this->delivery_monday) $str .= 'lundi, '; | |||
if ($this->delivery_tuesday) $str .= 'mardi, '; | |||
if ($this->delivery_wednesday) $str .= 'mercredi, '; | |||
if ($this->delivery_thursday) $str .= 'jeudi, '; | |||
if ($this->delivery_friday) $str .= 'vendredi, '; | |||
if ($this->delivery_saturday) $str .= 'samedi, '; | |||
if ($this->delivery_sunday) $str .= 'dimanche, '; | |||
if (strlen($str)) { | |||
return substr($str, 0, strlen($str) - 2); | |||
} else { | |||
return ''; | |||
} | |||
/** | |||
* Retourne un commentaire informant l'utilisateur sur les détails de | |||
* livraison d'un point de vente et pour un jour donné. | |||
* | |||
* @param string $jour | |||
* @return string | |||
*/ | |||
public function getStrInfos($day) | |||
{ | |||
$str = ''; | |||
$field = 'infos_' . $day; | |||
if (strlen($this->$field)) { | |||
$str = nl2br(Html::encode($this->$field)); | |||
$str = preg_replace('/\[select_previous_day\](.*?)\[\/select_previous_day\]/', '<a href="javascript:void(0);" class="select-previous-day">$1</a>', $str); | |||
} | |||
return $str; | |||
} | |||
/** | |||
* Retourne un commentaire informant l'utilisateur sur les détails de | |||
* livraison d'un point de vente et pour un jour donné. | |||
* | |||
* @param string $jour | |||
* @return string | |||
*/ | |||
public function getStrInfos($day) | |||
{ | |||
$str = ''; | |||
$field = 'infos_' . $day; | |||
if (strlen($this->$field)) { | |||
$str = nl2br(Html::encode($this->$field)); | |||
$str = preg_replace('/\[select_previous_day\](.*?)\[\/select_previous_day\]/', '<a href="javascript:void(0);" class="select-previous-day">$1</a>', $str); | |||
} | |||
/** | |||
* Retourne le mode de fonctionnement du crédit du point de vente. | |||
* | |||
* @return string | |||
*/ | |||
public function getCreditFunctioning() | |||
{ | |||
return strlen($this->credit_functioning) > 0 ? | |||
$this->credit_functioning : | |||
Producer::getConfig('credit_functioning'); | |||
return $str; | |||
} | |||
/** | |||
* Retourne le mode de fonctionnement du crédit du point de vente. | |||
* | |||
* @return string | |||
*/ | |||
public function getCreditFunctioning() | |||
{ | |||
return strlen($this->credit_functioning) > 0 ? | |||
$this->credit_functioning : | |||
Producer::getConfig('credit_functioning'); | |||
} | |||
/** | |||
* Lie un utilisateur au point de vente. | |||
* | |||
* @param integer $idUser | |||
*/ | |||
public function linkUser($idUser) | |||
{ | |||
if ($idUser) { | |||
$userPointSale = UserPointSale::find() | |||
->where([ | |||
'id_user' => $idUser, | |||
'id_point_sale' => $this->id | |||
])->one(); | |||
if (!$userPointSale) { | |||
$userPointSale = new UserPointSale; | |||
$userPointSale->id_user = $idUser; | |||
$userPointSale->id_point_sale = $this->id; | |||
$userPointSale->save(); | |||
} | |||
} | |||
} | |||
/** | |||
* Lie un utilisateur au point de vente. | |||
* | |||
* @param integer $idUser | |||
*/ | |||
public function linkUser($idUser) | |||
{ | |||
if ($idUser) { | |||
$userPointSale = UserPointSale::find() | |||
->where([ | |||
'id_user' => $idUser, | |||
'id_point_sale' => $this->id | |||
])->one(); | |||
public static function populateDropdownList() | |||
{ | |||
$pointSalesArrayDropdown = ['' => '--']; | |||
$pointSalesArray = PointSale::find()->where('id_producer = ' . GlobalParam::getCurrentProducerId())->all(); | |||
if (!$userPointSale) { | |||
$userPointSale = new UserPointSale; | |||
$userPointSale->id_user = $idUser; | |||
$userPointSale->id_point_sale = $this->id; | |||
$userPointSale->save(); | |||
} | |||
} | |||
foreach ($pointSalesArray as $pointSale) { | |||
$pointSalesArrayDropdown[$pointSale['id']] = $pointSale['name']; | |||
} | |||
public static function populateDropdownList() | |||
{ | |||
$pointSalesArrayDropdown = ['' => '--'] ; | |||
$pointSalesArray = PointSale::find()->where('id_producer = ' . GlobalParam::getCurrentProducerId())->all() ; | |||
foreach($pointSalesArray as $pointSale) { | |||
$pointSalesArrayDropdown[$pointSale['id']] = $pointSale['name'] ; | |||
} | |||
return $pointSalesArrayDropdown ; | |||
} | |||
return $pointSalesArrayDropdown; | |||
} | |||
} |
@@ -4,6 +4,7 @@ namespace common\logic\PointSale\PointSale; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\SolverInterface; | |||
class PointSaleBuilder extends BaseService implements BuilderInterface | |||
@@ -14,4 +15,27 @@ class PointSaleBuilder extends BaseService implements BuilderInterface | |||
return $pointSale; | |||
} | |||
/** | |||
* Initialise les commandes liées au point de vente. | |||
*/ | |||
public function initOrders(PointSale $pointSale, array $ordersArray): void | |||
{ | |||
$pointSale->orders = []; | |||
$pointSale->revenues = 0; | |||
$pointSale->revenues_with_tax = 0; | |||
if ($ordersArray) { | |||
foreach ($ordersArray as $order) { | |||
if ($pointSale->id == $order->id_point_sale) { | |||
$pointSale->orders[] = $order; | |||
if (is_null($order->date_delete)) { | |||
$pointSale->revenues += (float) $order->amount; | |||
$pointSale->revenues_with_tax += (float) $order->amount_with_tax; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -10,10 +10,20 @@ use common\logic\RepositoryInterface; | |||
class PointSaleRepository extends BaseService implements RepositoryInterface | |||
{ | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => [], | |||
'orderby' => 'is_bread_box ASC, name ASC', | |||
'attribute_id_producer' => 'point_sale.id_producer' | |||
]; | |||
} | |||
public function getByDistribution(Distribution $distribution) | |||
{ | |||
return PointSale::find() | |||
->with(['pointSaleDistribution' => function($q) use ($distribution) { | |||
->with(['pointSaleDistribution' => function ($q) use ($distribution) { | |||
$q->where(['id_distribution' => $distribution->id]); | |||
}]) | |||
->where([ |
@@ -97,5 +97,4 @@ class UserPointSale extends ActiveRecordCommon | |||
'attribute_id_producer' => '' | |||
] ; | |||
} | |||
} |
@@ -6,6 +6,7 @@ use common\helpers\Departments; | |||
use common\helpers\GlobalParam; | |||
use common\helpers\Price; | |||
use common\logic\BaseService; | |||
use common\logic\Document\Document\DocumentInterface; | |||
use common\logic\Producer\ProducerPriceRange\ProducerPriceRange; | |||
use common\logic\Producer\ProducerPriceRange\ProducerPriceRangeRepository; | |||
use common\logic\RepositoryInterface; | |||
@@ -248,4 +249,11 @@ class ProducerRepository extends BaseService implements RepositoryInterface | |||
$producer = $this->getOneById($user->id_producer); | |||
return $producer->getName(); | |||
} | |||
public function isDocumentDisplayOrders(DocumentInterface $document): bool | |||
{ | |||
return ($document->getClass() == 'Invoice') ? | |||
$this->getConfig('document_display_orders_invoice') : | |||
$this->getConfig('document_display_orders_delivery_note'); | |||
} | |||
} |
@@ -4,6 +4,9 @@ namespace common\logic\User\CreditHistory; | |||
use common\logic\BaseService; | |||
use common\logic\BuilderInterface; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\Producer\Producer\Producer; | |||
use common\logic\User\User\User; | |||
use common\logic\User\UserProducer\UserProducerBuilder; | |||
class CreditHistoryBuilder extends BaseService implements BuilderInterface | |||
@@ -17,19 +20,36 @@ class CreditHistoryBuilder extends BaseService implements BuilderInterface | |||
$this->userProducerBuilder = $this->loadService(UserProducerBuilder::class); | |||
} | |||
public function instanciate(): CreditHistory | |||
public function instanciate(string $type, float $amount, Producer $producer, User $user, User $userAction, Order $order = null): CreditHistory | |||
{ | |||
$creditHistory = new CreditHistory(); | |||
$creditHistory = new CreditHistory; | |||
$creditHistory->type = $type; | |||
$creditHistory->amount = round($amount, 2); | |||
$creditHistory->id_producer = $producer->id; | |||
$creditHistory->populateRelation('producer', $producer); | |||
$creditHistory->id_user = $user->id; | |||
$creditHistory->populateRelation('user', $user); | |||
$creditHistory->id_user_action = $userAction->id; | |||
$creditHistory->populateRelation('userAction', $userAction); | |||
if($order) { | |||
$creditHistory->id_order = $order->id; | |||
$creditHistory->populateRelation('order', $order); | |||
} | |||
return $creditHistory; | |||
} | |||
public function save(CreditHistory $creditHistory): bool | |||
// saveCreditHistory | |||
public function create(string $type, float $amount, Producer $producer, User $user, User $userAction, Order $order = null): ?CreditHistory | |||
{ | |||
if ($creditHistory->getAmount() > -0.01 && $creditHistory->getAmount() < 0.01) { | |||
return false; | |||
if ($amount > -0.01 && $amount < 0.01) { | |||
return null; | |||
} | |||
$creditHistory = $this->instanciate($type, $amount, $producer, $user, $userAction, $order); | |||
// Initialisation du commentaire avant sauvegarde | |||
$creditHistory->setComment($creditHistory->getComment() . $this->creditHistorySolver->getStrComment($creditHistory)); | |||
@@ -38,6 +58,6 @@ class CreditHistoryBuilder extends BaseService implements BuilderInterface | |||
// Mise à jour du crédit au niveau de UserProducer | |||
$this->userProducerBuilder->updateCredit($creditHistory); | |||
return true; | |||
return $creditHistory; | |||
} | |||
} |
@@ -3,16 +3,12 @@ | |||
namespace common\logic\User\CreditHistory; | |||
use common\logic\BaseService; | |||
use common\logic\Order\Order\Order; | |||
use common\logic\RepositoryInterface; | |||
class CreditHistoryRepository extends BaseService implements RepositoryInterface | |||
{ | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
public function defaultOptionsSearch(): array | |||
{ | |||
return [ | |||
'with' => [], | |||
@@ -21,4 +17,11 @@ class CreditHistoryRepository extends BaseService implements RepositoryInterface | |||
'attribute_id_producer' => CreditHistory::tableName() . '.id_producer' | |||
]; | |||
} | |||
public function getByOrder(Order $order) | |||
{ | |||
return CreditHistory::find() | |||
->where(['id_order' => $order->id]) | |||
->all(); | |||
} | |||
} |
@@ -58,8 +58,8 @@ class CreditHistorySolver implements SolverInterface | |||
if (CreditHistory::TYPE_PAYMENT == $type || CreditHistory::TYPE_REFUND == $type) { | |||
$order = $creditHistory->getOrderObject(); | |||
if ($order && $order->getDistributionOject()) { | |||
$str .= '<br />Commande : ' . date('d/m/Y', strtotime($order->getDistributionOject()->getDate())); | |||
if ($order && $order->distribution) { | |||
$str .= '<br />Commande : ' . date('d/m/Y', strtotime($order->distribution->date)); | |||
} else { | |||
$str .= '<br />Commande supprimée'; | |||
} |