->joinWith($defaultOptionsSearch['join_with']) | ->joinWith($defaultOptionsSearch['join_with']) | ||||
->orderBy('distribution.date ASC'); | ->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; | |||||
} | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\BuilderInterface; | 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 | 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; | |||||
} | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Order\Order\Order; | use common\logic\Order\Order\Order; | ||||
use common\logic\Producer\Producer\Producer; | |||||
use common\logic\SolverInterface; | use common\logic\SolverInterface; | ||||
class DocumentSolver extends BaseService implements SolverInterface | class DocumentSolver extends BaseService implements SolverInterface | ||||
{ | { | ||||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); | 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; | |||||
} | |||||
} | } |
namespace common\logic\Document\Document; | namespace common\logic\Document\Document; | ||||
use common\helpers\GlobalParam; | |||||
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Producer\Producer\ProducerRepository; | |||||
use common\logic\Producer\Producer\ProducerSolver; | |||||
use common\logic\UtilsInterface; | use common\logic\UtilsInterface; | ||||
use kartik\mpdf\Pdf; | |||||
use yii\base\ErrorException; | |||||
use yii\helpers\Html; | |||||
class DocumentUtils extends BaseService implements UtilsInterface | 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; | |||||
} | |||||
} | } |
<?php | <?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; | namespace common\logic\Document\Invoice; | ||||
/** | /** | ||||
* This is the model class for table "invoice". | * 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 | 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'); | |||||
} | |||||
} | } |
class InvoiceRepository extends BaseService implements 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' | |||||
]; | |||||
} | |||||
} | } |
<?php | <?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; | namespace common\logic\Document\Quotation; | ||||
/** | /** | ||||
* This is the model class for table "quotation". | * 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 | 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'); | |||||
} | |||||
} | } |
class QuotationRepository extends BaseService implements 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' | |||||
]; | |||||
} | |||||
} | } |
namespace common\logic\Order\Order; | namespace common\logic\Order\Order; | ||||
use common\helpers\GlobalParam; | |||||
use common\helpers\Price; | |||||
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\BuilderInterface; | 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 | 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 | public function instanciate(): Order | ||||
{ | { | ||||
$order = new Order(); | $order = new Order(); | ||||
return $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); | |||||
} | |||||
} | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Distribution\Distribution\Distribution; | 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 common\logic\RepositoryInterface; | ||||
use yii\helpers\Html; | |||||
class OrderRepository extends BaseService implements RepositoryInterface | 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 | public function defaultOptionsSearch(): array | ||||
{ | { | ||||
return [ | return [ | ||||
]; | ]; | ||||
} | } | ||||
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 = '') | public function getByDistribution(Distribution $distribution, string $conditionAppend = '') | ||||
{ | { | ||||
return Order::searchAll([ | return Order::searchAll([ | ||||
'conditions' => 'date_delete IS NULL ' . $conditionAppend | '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(); | |||||
} | |||||
} | } |
namespace common\logic\Order\Order; | namespace common\logic\Order\Order; | ||||
use common\helpers\GlobalParam; | |||||
use common\helpers\Price; | |||||
use common\logic\BaseService; | 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 common\logic\SolverInterface; | ||||
use yii\helpers\Html; | |||||
class OrderSolver extends BaseService implements SolverInterface | 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; | |||||
} | |||||
} | |||||
} | } |
namespace common\logic\Order\OrderStatusHistory; | namespace common\logic\Order\OrderStatusHistory; | ||||
use common\components\ActiveRecordCommon; | 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 | 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']); | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\BuilderInterface; | 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 | 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 = 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; | return $orderStatusHistory; | ||||
} | } | ||||
public function create(Order $order, User $user, string $status, string $origin): OrderStatusHistory | |||||
{ | |||||
$orderStatusHistory = $this->instanciate($order, $user, $status, $origin); | |||||
$orderStatusHistory->save(); | |||||
} | |||||
} | } |
class OrderStatusHistoryRepository extends BaseService implements RepositoryInterface | class OrderStatusHistoryRepository extends BaseService implements RepositoryInterface | ||||
{ | { | ||||
public function defaultOptionsSearch(): array | |||||
{ | |||||
return [ | |||||
'with' => [], | |||||
'join_with' => ['order', 'orderStatus'], | |||||
'orderby' => 'date ASC', | |||||
'attribute_id_producer' => '' | |||||
]; | |||||
} | |||||
} | } |
use common\helpers\GlobalParam; | use common\helpers\GlobalParam; | ||||
use common\helpers\Price; | use common\helpers\Price; | ||||
use common\components\ActiveRecordCommon; | 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". | * 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 | 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; | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\BuilderInterface; | use common\logic\BuilderInterface; | ||||
use common\logic\Order\Order\Order; | |||||
use common\logic\PointSale\PointSale\PointSale; | use common\logic\PointSale\PointSale\PointSale; | ||||
use common\logic\Product\Product\ProductSolver; | use common\logic\Product\Product\ProductSolver; | ||||
use common\logic\User\User\User; | use common\logic\User\User\User; | ||||
return $productOrder; | 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]); | |||||
} | |||||
} | } |
namespace common\logic\PointSale\PointSale; | namespace common\logic\PointSale\PointSale; | ||||
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Order\Order\Order; | |||||
use common\logic\Order\ProductOrder\ProductOrder; | |||||
use common\logic\RepositoryInterface; | use common\logic\RepositoryInterface; | ||||
class ProductOrderRepository extends BaseService implements 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() | |||||
} | |||||
} | } |
namespace common\logic\Order\ProductOrder; | namespace common\logic\Order\ProductOrder; | ||||
use common\helpers\Price; | |||||
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Order\Order\Order; | |||||
use common\logic\SolverInterface; | use common\logic\SolverInterface; | ||||
class ProductOrderSolver extends BaseService implements 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; | |||||
} | |||||
} | } |
namespace common\logic\PointSale\PointSale; | namespace common\logic\PointSale\PointSale; | ||||
use common\helpers\GlobalParam; | 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\Producer\Producer\Producer; | ||||
use common\logic\User\User\User; | |||||
use yii\helpers\Html; | use yii\helpers\Html; | ||||
use common\components\ActiveRecordCommon; | 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 | 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; | 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; | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\BuilderInterface; | use common\logic\BuilderInterface; | ||||
use common\logic\Order\Order\Order; | |||||
use common\logic\SolverInterface; | use common\logic\SolverInterface; | ||||
class PointSaleBuilder extends BaseService implements BuilderInterface | class PointSaleBuilder extends BaseService implements BuilderInterface | ||||
return $pointSale; | 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; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } |
class PointSaleRepository extends BaseService implements 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) | public function getByDistribution(Distribution $distribution) | ||||
{ | { | ||||
return PointSale::find() | return PointSale::find() | ||||
->with(['pointSaleDistribution' => function($q) use ($distribution) { | |||||
->with(['pointSaleDistribution' => function ($q) use ($distribution) { | |||||
$q->where(['id_distribution' => $distribution->id]); | $q->where(['id_distribution' => $distribution->id]); | ||||
}]) | }]) | ||||
->where([ | ->where([ |
'attribute_id_producer' => '' | 'attribute_id_producer' => '' | ||||
] ; | ] ; | ||||
} | } | ||||
} | } |
use common\helpers\GlobalParam; | use common\helpers\GlobalParam; | ||||
use common\helpers\Price; | use common\helpers\Price; | ||||
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Document\Document\DocumentInterface; | |||||
use common\logic\Producer\ProducerPriceRange\ProducerPriceRange; | use common\logic\Producer\ProducerPriceRange\ProducerPriceRange; | ||||
use common\logic\Producer\ProducerPriceRange\ProducerPriceRangeRepository; | use common\logic\Producer\ProducerPriceRange\ProducerPriceRangeRepository; | ||||
use common\logic\RepositoryInterface; | use common\logic\RepositoryInterface; | ||||
$producer = $this->getOneById($user->id_producer); | $producer = $this->getOneById($user->id_producer); | ||||
return $producer->getName(); | 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'); | |||||
} | |||||
} | } |
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\BuilderInterface; | 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; | use common\logic\User\UserProducer\UserProducerBuilder; | ||||
class CreditHistoryBuilder extends BaseService implements BuilderInterface | class CreditHistoryBuilder extends BaseService implements BuilderInterface | ||||
$this->userProducerBuilder = $this->loadService(UserProducerBuilder::class); | $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; | 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 | // Initialisation du commentaire avant sauvegarde | ||||
$creditHistory->setComment($creditHistory->getComment() . $this->creditHistorySolver->getStrComment($creditHistory)); | $creditHistory->setComment($creditHistory->getComment() . $this->creditHistorySolver->getStrComment($creditHistory)); | ||||
// Mise à jour du crédit au niveau de UserProducer | // Mise à jour du crédit au niveau de UserProducer | ||||
$this->userProducerBuilder->updateCredit($creditHistory); | $this->userProducerBuilder->updateCredit($creditHistory); | ||||
return true; | |||||
return $creditHistory; | |||||
} | } | ||||
} | } |
namespace common\logic\User\CreditHistory; | namespace common\logic\User\CreditHistory; | ||||
use common\logic\BaseService; | use common\logic\BaseService; | ||||
use common\logic\Order\Order\Order; | |||||
use common\logic\RepositoryInterface; | use common\logic\RepositoryInterface; | ||||
class CreditHistoryRepository extends BaseService implements 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 [ | return [ | ||||
'with' => [], | 'with' => [], | ||||
'attribute_id_producer' => CreditHistory::tableName() . '.id_producer' | 'attribute_id_producer' => CreditHistory::tableName() . '.id_producer' | ||||
]; | ]; | ||||
} | } | ||||
public function getByOrder(Order $order) | |||||
{ | |||||
return CreditHistory::find() | |||||
->where(['id_order' => $order->id]) | |||||
->all(); | |||||
} | |||||
} | } |
if (CreditHistory::TYPE_PAYMENT == $type || CreditHistory::TYPE_REFUND == $type) { | if (CreditHistory::TYPE_PAYMENT == $type || CreditHistory::TYPE_REFUND == $type) { | ||||
$order = $creditHistory->getOrderObject(); | $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 { | } else { | ||||
$str .= '<br />Commande supprimée'; | $str .= '<br />Commande supprimée'; | ||||
} | } |