Bläddra i källkod

Refactoring services #885

refactoring
Guillaume 1 år sedan
förälder
incheckning
77d0450c7a
27 ändrade filer med 1900 tillägg och 1905 borttagningar
  1. +0
    -280
      common/logic/Document/Document/Document.php
  2. +63
    -0
      common/logic/Document/Document/DocumentBuilder.php
  3. +114
    -0
      common/logic/Document/Document/DocumentSolver.php
  4. +120
    -0
      common/logic/Document/Document/DocumentUtils.php
  5. +53
    -80
      common/logic/Document/Invoice/Invoice.php
  6. +9
    -1
      common/logic/Document/Invoice/InvoiceRepository.php
  7. +47
    -73
      common/logic/Document/Quotation/Quotation.php
  8. +9
    -1
      common/logic/Document/Quotation/QuotationRepository.php
  9. +50
    -938
      common/logic/Order/Order/Order.php
  10. +309
    -1
      common/logic/Order/Order/OrderBuilder.php
  11. +203
    -0
      common/logic/Order/Order/OrderRepository.php
  12. +358
    -0
      common/logic/Order/Order/OrderSolver.php
  13. +51
    -69
      common/logic/Order/OrderStatusHistory/OrderStatusHistory.php
  14. +25
    -1
      common/logic/Order/OrderStatusHistory/OrderStatusHistoryBuilder.php
  15. +9
    -1
      common/logic/Order/OrderStatusHistory/OrderStatusHistoryRepository.php
  16. +73
    -109
      common/logic/Order/ProductOrder/ProductOrder.php
  17. +17
    -0
      common/logic/Order/ProductOrder/ProductOrderBuilder.php
  18. +15
    -0
      common/logic/Order/ProductOrder/ProductOrderRepository.php
  19. +17
    -0
      common/logic/Order/ProductOrder/ProductOrderSolver.php
  20. +278
    -335
      common/logic/PointSale/PointSale/PointSale.php
  21. +24
    -0
      common/logic/PointSale/PointSale/PointSaleBuilder.php
  22. +11
    -1
      common/logic/PointSale/PointSale/PointSaleRepository.php
  23. +0
    -1
      common/logic/PointSale/UserPointSale/UserPointSale.php
  24. +8
    -0
      common/logic/Producer/Producer/ProducerRepository.php
  25. +26
    -6
      common/logic/User/CreditHistory/CreditHistoryBuilder.php
  26. +9
    -6
      common/logic/User/CreditHistory/CreditHistoryRepository.php
  27. +2
    -2
      common/logic/User/CreditHistory/CreditHistorySolver.php

+ 0
- 280
common/logic/Document/Document/Document.php Visa fil

@@ -121,284 +121,4 @@ class Document extends ActiveRecordCommon implements DocumentInterface
->joinWith($defaultOptionsSearch['join_with'])
->orderBy('distribution.date ASC');
}

/*
* Méthodes
*/



public function generateReference()
{
$class = $this->getClass();
$classLower = strtolower($class);
if ($classLower == 'deliverynote') {
$classLower = 'delivery_note';
}

$prefix = Producer::getConfig('document_' . $classLower . '_prefix');
$oneDocumentExist = $class::searchOne(['status' => Document::STATUS_VALID], ['orderby' => 'reference DESC']);

if ($oneDocumentExist) {
$reference = $oneDocumentExist->reference;
$pattern = '#([A-Z]+)?([0-9]+)#';
preg_match($pattern, $reference, $matches, PREG_OFFSET_CAPTURE);
$sizeNumReference = strlen($matches[2][0]);
$numReference = ((int)$matches[2][0]) + 1;
$numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT);

return $prefix . $numReference;
} else {
$firstReference = Producer::getConfig('document_' . $classLower . '_first_reference');

if (strlen($firstReference) > 0) {
return $firstReference;
} else {
return $prefix . '00001';
}
}
}

public function downloadPdf($regenerate = false)
{
$filenameComplete = $this->getFilenameComplete();

if (!file_exists($filenameComplete) || $this->isStatusDraft() || $regenerate) {
$this->generatePdf(Pdf::DEST_FILE);
}

if (file_exists($filenameComplete)) {
return Yii::$app->response->sendFile($filenameComplete, $this->getFilename(), ['inline' => true]);
} else {
throw new ErrorException('File ' . $filenameComplete . ' not found');
}
}

public function generatePdf($destination)
{
$producer = $this->producer;
$content = Yii::$app->controller->renderPartial('/document/download', [
'producer' => $producer,
'document' => $this
]);

$contentFooter = '<div id="footer">';
$contentFooter .= '<div class="infos-bottom">' . Html::encode($producer->document_infos_bottom) . '</div>';
if ($this->isStatusValid() || $this->isStatusDraft()) {
$contentFooter .= '<div class="reference-document">';
if ($this->isStatusValid()) {
$contentFooter .= $this->getType() . ' N°' . $this->reference;
}
if ($this->isStatusDraft()) {
$contentFooter .= $this->getType() . ' non validé';
if ($this->getType() == 'Facture') {
$contentFooter .= 'e';
}
}
$contentFooter .= '</div>';
}
$contentFooter .= '</div>';

$marginBottom = 10;
if (strlen(Producer::getConfig('document_infos_bottom')) > 0) {
$marginBottom = 40;
}

$this->initDirectoryPdf();

$pdf = new Pdf([
'mode' => Pdf::MODE_UTF8,
'format' => Pdf::FORMAT_A4,
'orientation' => Pdf::ORIENT_PORTRAIT,
'destination' => $destination,
'content' => $content,
'filename' => $this->getFilenameComplete(),
'cssFile' => Yii::getAlias('@webroot/css/document/download.css'),
'marginBottom' => $marginBottom,
'methods' => [
'SetHTMLFooter' => $contentFooter
]
]);

return $pdf->render();
}

public function send()
{
if (isset($this->user) && strlen($this->user->email) > 0) {
$producer = GlobalParam::getCurrentProducer();

$subjectEmail = $this->getType();
if ($this->isStatusValid()) {
$subjectEmail .= ' N°' . $this->reference;
}

$email = Yii::$app->mailer->compose(
[
'html' => 'sendDocument-html',
'text' => 'sendDocument-text'
], [
'document' => $this,
])
->setTo($this->user->email)
->setFrom([$producer->getEmailOpendistrib() => $producer->name])
->setSubject('[' . $producer->name . '] ' . $subjectEmail);

$this->generatePdf(Pdf::DEST_FILE);
$email->attach($this->getFilenameComplete());

return $email->send();
}

return false;
}

public function changeStatus($status)
{
if ($status == Document::STATUS_VALID) {
$this->status = $status;
$this->reference = $this->generateReference();
}
}

public function getStatusWording()
{
return ($this->status == self::STATUS_DRAFT) ? 'Brouillon' : 'Validé';
}

public function getStatusCssClass()
{
return ($this->status == self::STATUS_DRAFT) ? 'default' : 'success';
}

public function getHtmlLabel()
{
$label = $this->getStatusWording();
$classLabel = $this->getStatusCssClass();
return '<span class="label label-' . $classLabel . '">' . $label . '</span>';
}

public function isStatus($status)
{
return $this->status == $status;
}

public function isStatusDraft()
{
return $this->isStatus(self::STATUS_DRAFT);
}

public function isStatusValid()
{
return $this->isStatus(self::STATUS_VALID);
}

public function getProductsOrders()
{
$productsOrdersArray = [];
$ordersArray = $this->orders;
if ($ordersArray && count($ordersArray)) {
foreach ($ordersArray as $order) {
foreach ($order->productOrder as $productOrder) {
if ($productOrder->product) {
$indexProductOrder = $productOrder->product->order;
$newProductOrder = clone $productOrder;

if (!isset($productsOrdersArray[$indexProductOrder])) {
$productsOrdersArray[$indexProductOrder] = [$newProductOrder];
} else {
$productOrderMatch = false;
foreach ($productsOrdersArray[$indexProductOrder] as &$theProductOrder) {
if ($theProductOrder->unit == $productOrder->unit
&& $theProductOrder->price == $productOrder->price
&& $theProductOrder->invoice_price == $productOrder->invoice_price) {

$theProductOrder->quantity += $productOrder->quantity;
$productOrderMatch = true;
}
}
if (!$productOrderMatch) {
$productsOrdersArray[$indexProductOrder][] = $newProductOrder;
}
}
}
}
}
}

// tri des orderProduct par product.order
ksort($productsOrdersArray);

return $productsOrdersArray;
}

public function isDisplayOrders()
{
$displayOrders = ($this->getClass() == 'Invoice') ?
Producer::getConfig('document_display_orders_invoice') :
Producer::getConfig('document_display_orders_delivery_note');

return $displayOrders;
}

public function getAliasDirectoryBase()
{
return '@app/web/pdf/' . $this->id_producer . '/';
}

public function initDirectoryPdf()
{
$aliasDirectoryBase = $this->getAliasDirectoryBase();
$directoryPdf = Yii::getAlias($aliasDirectoryBase);
if (!file_exists($directoryPdf)) {
mkdir($directoryPdf, 0755);
}
}

public function getFilename()
{
$filename = $this->getType() . '-';

if($this->isStatusValid()) {
$filename .= $this->reference;
}
elseif($this->isStatusDraft()) {
$filename .= 'Brouillon-'.$this->id;
}

$filename .= '.pdf';

return $filename;
}

public function getFilenameComplete()
{
return Yii::getAlias($this->getAliasDirectoryBase() . $this->getFilename());
}

public function isInvoicePrice()
{
return $this->getClass() == 'Invoice' || $this->getClass() == 'DeliveryNote';
}

public function isTaxCalculationMethodSumOfRoundings()
{
return $this->tax_calculation_method == self::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS;
}

public function isTaxCalculationMethodRoundingOfTheSum()
{
return $this->tax_calculation_method == self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM;
}

public function initTaxCalculationMethod()
{
$producerTaxCalculationMethod = Producer::getConfig('option_tax_calculation_method');

if ($producerTaxCalculationMethod) {
$this->tax_calculation_method = $producerTaxCalculationMethod;
} else {
$this->tax_calculation_method = self::TAX_CALCULATION_METHOD_DEFAULT;
}
}
}

+ 63
- 0
common/logic/Document/Document/DocumentBuilder.php Visa fil

@@ -4,8 +4,71 @@ namespace common\logic\Document\Document;

use common\logic\BaseService;
use common\logic\BuilderInterface;
use common\logic\Producer\Producer\Producer;
use common\logic\Producer\Producer\ProducerRepository;
use kartik\mpdf\Pdf;
use yii\helpers\Html;

class DocumentBuilder extends BaseService implements BuilderInterface
{
protected DocumentSolver $documentSolver;
protected ProducerRepository $producerRepository;

public function __construct()
{
$this->documentSolver = $this->loadService(DocumentSolver::class);
$this->producerRepository = $this->loadService(ProducerRepository::class);
}

public function generateReference(DocumentInterface $document): void
{
$class = $document->getClass();
$classLower = strtolower($class);
if ($classLower == 'deliverynote') {
$classLower = 'delivery_note';
}

$prefix = $this->producerRepository->getConfig('document_' . $classLower . '_prefix');
$oneDocumentExist = $class::searchOne(['status' => Document::STATUS_VALID], ['orderby' => 'reference DESC']);

if ($oneDocumentExist) {
$referenceDocument = $oneDocumentExist->reference;
$pattern = '#([A-Z]+)?([0-9]+)#';
preg_match($pattern, $referenceDocument, $matches, PREG_OFFSET_CAPTURE);
$sizeNumReference = strlen($matches[2][0]);
$numReference = ((int)$matches[2][0]) + 1;
$numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT);

$reference = $prefix . $numReference;
} else {
$firstReference = $this->producerRepository->getConfig('document_' . $classLower . '_first_reference');

if (strlen($firstReference) > 0) {
$reference = $firstReference;
} else {
$reference = $prefix . '00001';
}
}

$document->reference = $reference;
}

public function changeStatus(DocumentInterface $document, string $status): void
{
if ($status == Document::STATUS_VALID) {
$document->status = $status;
$this->generateReference($document);
}
}

public function initTaxCalculationMethod(DocumentInterface $document): void
{
$producerTaxCalculationMethod = $this->producerRepository->getConfig('option_tax_calculation_method');

if ($producerTaxCalculationMethod) {
$document->tax_calculation_method = $producerTaxCalculationMethod;
} else {
$document->tax_calculation_method = Document::TAX_CALCULATION_METHOD_DEFAULT;
}
}
}

+ 114
- 0
common/logic/Document/Document/DocumentSolver.php Visa fil

@@ -4,6 +4,7 @@ namespace common\logic\Document\Document;

use common\logic\BaseService;
use common\logic\Order\Order\Order;
use common\logic\Producer\Producer\Producer;
use common\logic\SolverInterface;

class DocumentSolver extends BaseService implements SolverInterface
@@ -116,4 +117,117 @@ class DocumentSolver extends BaseService implements SolverInterface
{
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']);
}

public function getStatusWording(DocumentInterface $document): string
{
return ($document->status == Document::STATUS_DRAFT) ? 'Brouillon' : 'Validé';
}

public function getStatusCssClass(DocumentInterface $document): string
{
return ($document->status == Document::STATUS_DRAFT) ? 'default' : 'success';
}

public function getHtmlLabel(DocumentInterface $document)
{
$label = $this->getStatusWording($document);
$classLabel = $this->getStatusCssClass($document);

return '<span class="label label-' . $classLabel . '">' . $label . '</span>';
}

public function isStatus(DocumentInterface $document, string $status): bool
{
return $document->status == $status;
}

public function isStatusDraft(DocumentInterface $document): bool
{
return $this->isStatus($document, Document::STATUS_DRAFT);
}

public function isStatusValid(DocumentInterface $document): bool
{
return $this->isStatus($document, Document::STATUS_VALID);
}

public function getProductsOrders(DocumentInterface $document): array
{
$productsOrdersArray = [];
$ordersArray = $document->orders;
if ($ordersArray && count($ordersArray)) {
foreach ($ordersArray as $order) {
foreach ($order->productOrder as $productOrder) {
if ($productOrder->product) {
$indexProductOrder = $productOrder->product->order;
$newProductOrder = clone $productOrder;

if (!isset($productsOrdersArray[$indexProductOrder])) {
$productsOrdersArray[$indexProductOrder] = [$newProductOrder];
} else {
$productOrderMatch = false;
foreach ($productsOrdersArray[$indexProductOrder] as &$theProductOrder) {
if ($theProductOrder->unit == $productOrder->unit
&& $theProductOrder->price == $productOrder->price
&& $theProductOrder->invoice_price == $productOrder->invoice_price) {

$theProductOrder->quantity += $productOrder->quantity;
$productOrderMatch = true;
}
}
if (!$productOrderMatch) {
$productsOrdersArray[$indexProductOrder][] = $newProductOrder;
}
}
}
}
}
}

// tri des orderProduct par product.order
ksort($productsOrdersArray);

return $productsOrdersArray;
}

public function getAliasDirectoryBase(DocumentInterface $document): string
{
return '@app/web/pdf/' . $document->id_producer . '/';
}

public function getFilename(DocumentInterface $document): string
{
$filename = $document->getType() . '-';

if($this->isStatusValid($document)) {
$filename .= $document->reference;
}
elseif($this->isStatusDraft($document)) {
$filename .= 'Brouillon-'.$document->id;
}

$filename .= '.pdf';

return $filename;
}

public function getFilenameComplete(DocumentInterface $document): string
{
return \Yii::getAlias($this->getAliasDirectoryBase($document) . $this->getFilename($document));
}

public function isInvoicePrice(DocumentInterface $document): bool
{
return $this->getClass() == 'Invoice' || $this->getClass() == 'DeliveryNote';
}

public function isTaxCalculationMethodSumOfRoundings(DocumentInterface $document): bool
{
return $document->tax_calculation_method == self::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS;
}

public function isTaxCalculationMethodRoundingOfTheSum(DocumentInterface $document): bool
{
return $document->tax_calculation_method == self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM;
}
}

+ 120
- 0
common/logic/Document/Document/DocumentUtils.php Visa fil

@@ -2,10 +2,130 @@

namespace common\logic\Document\Document;

use common\helpers\GlobalParam;
use common\logic\BaseService;
use common\logic\Producer\Producer\ProducerRepository;
use common\logic\Producer\Producer\ProducerSolver;
use common\logic\UtilsInterface;
use kartik\mpdf\Pdf;
use yii\base\ErrorException;
use yii\helpers\Html;

class DocumentUtils extends BaseService implements UtilsInterface
{
protected DocumentSolver $documentSolver;
protected DocumentBuilder $documentBuilder;
protected ProducerSolver $producerSolver;
protected ProducerRepository $producerRepository;

public function __construct()
{
$this->documentSolver = $this->loadService(DocumentSolver::class);
$this->documentBuilder = $this->loadService(DocumentBuilder::class);
$this->producerSolver = $this->loadService(ProducerSolver::class);
$this->producerRepository = $this->loadService(ProducerRepository::class);
}

public function generatePdf(DocumentInterface $document, string $destination): string
{
$producer = $document->producer;
$content = \Yii::$app->controller->renderPartial('/document/download', [
'producer' => $producer,
'document' => $this
]);

$contentFooter = '<div id="footer">';
$contentFooter .= '<div class="infos-bottom">' . Html::encode($producer->document_infos_bottom) . '</div>';
if ($this->documentSolver->isStatusValid($document) || $this->documentSolver->isStatusDraft($document)) {
$contentFooter .= '<div class="reference-document">';
if ($this->documentSolver->isStatusValid($document)) {
$contentFooter .= $this->getType() . ' N°' . $document->reference;
}
if ($this->documentSolver->isStatusDraft($document)) {
$contentFooter .= $document->getType() . ' non validé';
if ($document->getType() == 'Facture') {
$contentFooter .= 'e';
}
}
$contentFooter .= '</div>';
}
$contentFooter .= '</div>';

$marginBottom = 10;
if (strlen($this->producerRepository->getConfig('document_infos_bottom')) > 0) {
$marginBottom = 40;
}

$this->initDirectoryPdf($document);

$pdf = new Pdf([
'mode' => Pdf::MODE_UTF8,
'format' => Pdf::FORMAT_A4,
'orientation' => Pdf::ORIENT_PORTRAIT,
'destination' => $destination,
'content' => $content,
'filename' => $this->documentSolver->getFilenameComplete($document),
'cssFile' => \Yii::getAlias('@webroot/css/document/download.css'),
'marginBottom' => $marginBottom,
'methods' => [
'SetHTMLFooter' => $contentFooter
]
]);

return $pdf->render();
}

public function initDirectoryPdf(DocumentInterface $document): void
{
$aliasDirectoryBase = $this->documentSolver->getAliasDirectoryBase($document);
$directoryPdf = \Yii::getAlias($aliasDirectoryBase);
if (!file_exists($directoryPdf)) {
mkdir($directoryPdf, 0755);
}
}

public function downloadPdf(DocumentInterface $document, $regenerate = false)
{
$filenameComplete = $this->documentSolver->getFilenameComplete($document);

if (!file_exists($filenameComplete) || $this->documentSolver->isStatusDraft($document) || $regenerate) {
$this->generatePdf($document, Pdf::DEST_FILE);
}

if (file_exists($filenameComplete)) {
return \Yii::$app->response->sendFile($filenameComplete, $this->documentSolver->getFilename($document), ['inline' => true]);
} else {
throw new ErrorException('File ' . $filenameComplete . ' not found');
}
}

public function send(DocumentInterface $document)
{
if (isset($document->user) && strlen($document->user->email) > 0) {
$producer = GlobalParam::getCurrentProducer();

$subjectEmail = $document->getType();
if ($this->documentSolver->isStatusValid($document)) {
$subjectEmail .= ' N°' . $document->reference;
}

$email = \Yii::$app->mailer->compose(
[
'html' => 'sendDocument-html',
'text' => 'sendDocument-text'
], [
'document' => $this,
])
->setTo($document->user->email)
->setFrom([$producer->getEmailOpendistrib() => $producer->name])
->setSubject('[' . $producer->name . '] ' . $subjectEmail);

$this->documentBuilder->generatePdf($document, Pdf::DEST_FILE);
$email->attach($this->documentSolver->getFilenameComplete($document));

return $email->send();
}

return false;
}
}

+ 53
- 80
common/logic/Document/Invoice/Invoice.php Visa fil

@@ -1,40 +1,40 @@
<?php

/**
Copyright distrib (2018)
contact@opendistrib.net
Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.
Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".
En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.
A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/
/**
* Copyright distrib (2018)
*
* contact@opendistrib.net
*
* Ce logiciel est un programme informatique servant à aider les producteurs
* à distribuer leur production en circuits courts.
*
* Ce logiciel est régi par la licence CeCILL soumise au droit français et
* respectant les principes de diffusion des logiciels libres. Vous pouvez
* utiliser, modifier et/ou redistribuer ce programme sous les conditions
* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
* sur le site "http://www.cecill.info".
*
* En contrepartie de l'accessibilité au code source et des droits de copie,
* de modification et de redistribution accordés par cette licence, il n'est
* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
* seule une responsabilité restreinte pèse sur l'auteur du programme, le
* titulaire des droits patrimoniaux et les concédants successifs.
*
* A cet égard l'attention de l'utilisateur est attirée sur les risques
* associés au chargement, à l'utilisation, à la modification et/ou au
* développement et à la reproduction du logiciel par l'utilisateur étant
* donné sa spécificité de logiciel libre, qui peut le rendre complexe à
* manipuler et qui le réserve donc à des développeurs et des professionnels
* avertis possédant des connaissances informatiques approfondies. Les
* utilisateurs sont donc invités à charger et tester l'adéquation du
* logiciel à leurs besoins dans des conditions permettant d'assurer la
* sécurité de leurs systèmes et ou de leurs données et, plus généralement,
* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
*
* Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
* pris connaissance de la licence CeCILL, et que vous en avez accepté les
* termes.
*/

namespace common\logic\Document\Invoice;

@@ -42,52 +42,25 @@ use common\logic\Document\Document\Document;

/**
* This is the model class for table "invoice".
*
* @property integer $id
* @property string $name
* @property string $reference
* @property string $date
* @property string $comment
* @property integer $id_user
* @property string $address
* @property string $city
* @property string $postcode
*/
class Invoice extends Document
{

public $deliveryNotes ;

/**
* @inheritdoc
*/
public static function tableName()
{
return 'invoice';
}

/*
* Relations
*/

public function getOrders()
{
return $this->relationOrders('id_invoice') ;
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => [],
'join_with' => ['user AS user_invoice', 'producer'],
'orderby' => 'date ASC',
'attribute_id_producer' => 'invoice.id_producer'
];
}

public $deliveryNotes;

/**
* @inheritdoc
*/
public static function tableName()
{
return 'invoice';
}

/*
* Relations
*/

public function getOrders()
{
return $this->relationOrders('id_invoice');
}
}

+ 9
- 1
common/logic/Document/Invoice/InvoiceRepository.php Visa fil

@@ -7,5 +7,13 @@ use common\logic\RepositoryInterface;

class InvoiceRepository extends BaseService implements RepositoryInterface
{

public function defaultOptionsSearch(): array
{
return [
'with' => [],
'join_with' => ['user AS user_invoice', 'producer'],
'orderby' => 'date ASC',
'attribute_id_producer' => 'invoice.id_producer'
];
}
}

+ 47
- 73
common/logic/Document/Quotation/Quotation.php Visa fil

@@ -1,39 +1,39 @@
<?php

/**
Copyright distrib (2018)
contact@opendistrib.net
Ce logiciel est un programme informatique servant à aider les producteurs
à distribuer leur production en circuits courts.
Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".
En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.
A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
* Copyright distrib (2018)
*
* contact@opendistrib.net
*
* Ce logiciel est un programme informatique servant à aider les producteurs
* à distribuer leur production en circuits courts.
*
* Ce logiciel est régi par la licence CeCILL soumise au droit français et
* respectant les principes de diffusion des logiciels libres. Vous pouvez
* utiliser, modifier et/ou redistribuer ce programme sous les conditions
* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
* sur le site "http://www.cecill.info".
*
* En contrepartie de l'accessibilité au code source et des droits de copie,
* de modification et de redistribution accordés par cette licence, il n'est
* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
* seule une responsabilité restreinte pèse sur l'auteur du programme, le
* titulaire des droits patrimoniaux et les concédants successifs.
*
* A cet égard l'attention de l'utilisateur est attirée sur les risques
* associés au chargement, à l'utilisation, à la modification et/ou au
* développement et à la reproduction du logiciel par l'utilisateur étant
* donné sa spécificité de logiciel libre, qui peut le rendre complexe à
* manipuler et qui le réserve donc à des développeurs et des professionnels
* avertis possédant des connaissances informatiques approfondies. Les
* utilisateurs sont donc invités à charger et tester l'adéquation du
* logiciel à leurs besoins dans des conditions permettant d'assurer la
* sécurité de leurs systèmes et ou de leurs données et, plus généralement,
* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
*
* Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
* pris connaissance de la licence CeCILL, et que vous en avez accepté les
* termes.
*/

namespace common\logic\Document\Quotation;
@@ -42,50 +42,24 @@ use common\logic\Document\Document\Document;

/**
* This is the model class for table "quotation".
*
* @property integer $id
* @property string $name
* @property string $reference
* @property string $date
* @property string $comment
* @property integer $id_user
* @property string $address
* @property string $city
* @property string $postcode
*/
class Quotation extends Document
{

/**
* @inheritdoc
*/
public static function tableName()
{
return 'quotation';
}

/*
* Relations
*/

public function getOrders()
{
return $this->relationOrders('id_quotation') ;
}
/**
* @inheritdoc
*/
public static function tableName()
{
return 'quotation';
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => [],
'join_with' => ['user AS user_quotation', 'producer'],
'orderby' => 'date ASC',
'attribute_id_producer' => 'quotation.id_producer'
];
}
/*
* Relations
*/

public function getOrders()
{
return $this->relationOrders('id_quotation');
}
}

+ 9
- 1
common/logic/Document/Quotation/QuotationRepository.php Visa fil

@@ -7,5 +7,13 @@ use common\logic\RepositoryInterface;

class QuotationRepository extends BaseService implements RepositoryInterface
{

public function defaultOptionsSearch(): array
{
return [
'with' => [],
'join_with' => ['user AS user_quotation', 'producer'],
'orderby' => 'date ASC',
'attribute_id_producer' => 'quotation.id_producer'
];
}
}

+ 50
- 938
common/logic/Order/Order/Order.php
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 309
- 1
common/logic/Order/Order/OrderBuilder.php Visa fil

@@ -2,16 +2,324 @@

namespace common\logic\Order\Order;

use common\helpers\GlobalParam;
use common\helpers\Price;
use common\logic\BaseService;
use common\logic\BuilderInterface;
use common\logic\SolverInterface;
use common\logic\Document\Document\Document;
use common\logic\Order\OrderStatusHistory\OrderStatusHistoryBuilder;
use common\logic\Order\ProductOrder\ProductOrder;
use common\logic\Order\ProductOrder\ProductOrderBuilder;
use common\logic\Producer\Producer\Producer;
use common\logic\Producer\Producer\ProducerRepository;
use common\logic\User\CreditHistory\CreditHistory;
use common\logic\User\CreditHistory\CreditHistoryBuilder;
use common\logic\User\CreditHistory\CreditHistoryRepository;
use common\logic\User\User\UserSolver;
use yii\web\NotFoundHttpException;

class OrderBuilder extends BaseService implements BuilderInterface
{
protected UserSolver $userSolver;
protected OrderSolver $orderSolver;
protected CreditHistoryRepository $creditHistoryRepository;
protected ProducerRepository $producerRepository;
protected CreditHistoryBuilder $creditHistoryBuilder;
protected ProductOrderBuilder $productOrderBuilder;
protected OrderStatusHistoryBuilder $orderStatusHistoryBuilder;
protected OrderRepository $orderRepository;

public function __construct()
{
$this->userSolver = $this->loadService(UserSolver::class);
$this->orderSolver = $this->loadService(OrderSolver::class);
$this->creditHistoryRepository = $this->loadService(CreditHistoryRepository::class);
$this->producerRepository = $this->loadService(ProducerRepository::class);
$this->creditHistoryBuilder = $this->loadService(CreditHistoryBuilder::class);
$this->productOrderBuilder = $this->loadService(ProductOrderBuilder::class);
$this->orderStatusHistoryBuilder = $this->loadService(OrderStatusHistoryBuilder::class);
$this->orderRepository = $this->loadService(OrderRepository::class);
}

public function instanciate(): Order
{
$order = new Order();

return $order;
}

/**
* Initialise le montant total, le montant déjà payé et le poids de la commande.
*/
public function init(Order $order, $taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT)
{
$this->initAmount($order, $taxCalculationMethod);
$this->initPaidAmount($order);

return $this;
}

/**
* Initialise le montant de la commande.
*/
public function initAmount(Order $order, $taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT)
{
$order->amount = 0;
$order->amount_with_tax = 0;
$order->amount_vat = [];
$order->invoice_amount = 0;
$order->invoice_amount_with_tax = 0;
$order->invoice_amount_vat = [];
$order->weight = 0;

if (isset($order->productOrder)) {
foreach ($order->productOrder as $productOrder) {
$this->addAmount($order, Order::AMOUNT_TOTAL, $productOrder, $taxCalculationMethod);
$this->addAmount($order, Order::INVOICE_AMOUNT_TOTAL, $productOrder, $taxCalculationMethod);
$this->addWeight($order, $productOrder);
}
}
}

public function addWeight(Order $order, ProductOrder $productOrder): void
{
if ($productOrder->unit == 'piece') {
if (isset($productOrder->product)) {
$order->weight += ($productOrder->quantity * $productOrder->product->weight) / 1000;
}
} else {
$order->weight += $productOrder->quantity;
}
}

public function addAmount(Order $order, $typeTotal, $productOrder, $taxCalculationMethod)
{
$fieldNameAmount = $this->getFieldNameAmount($typeTotal);
$fieldNameAmountWithTax = $this->getFieldNameAmount($typeTotal, 'with_tax');
$price = $productOrder->getPriceByTypeTotal($typeTotal);
$order->$fieldNameAmount += $price * $productOrder->quantity;
$order->$fieldNameAmountWithTax += Price::getPriceWithTax(
$price,
$productOrder->taxRate->value,
$taxCalculationMethod
) * $productOrder->quantity;
$order->addVat($order, $typeTotal, $price * $productOrder->quantity, $productOrder->taxRate, $taxCalculationMethod);
}

public function addVat($typeTotal, $priceTotalWithoutTax, $taxRate, $taxCalculationMethod)
{
$fieldName = $this->getFieldNameAmount($typeTotal, 'vat');

if (!isset($this->$fieldName[$taxRate->id])) {
$this->$fieldName[$taxRate->id] = 0;
}

$this->$fieldName[$taxRate->id] += Price::getVat($priceTotalWithoutTax, $taxRate->value, $taxCalculationMethod);
}

/**
* Initialise le montant payé de la commande et le retourne.
*/
public function initPaidAmount(Order $order): void
{
if (isset($order->creditHistory)) {
$history = $order->creditHistory;
} else {
$history = $this->creditHistoryRepository->getByOrder($order);
}

$order->paid_amount = 0;

if (count($history)) {
foreach ($history as $ch) {
if ($ch->type == CreditHistory::TYPE_PAYMENT) {
$order->paid_amount += $ch->amount;
} elseif ($ch->type == CreditHistory::TYPE_REFUND) {
$order->paid_amount -= $ch->amount;
}
}
}
}

public function delete(Order $order, $force = false)
{
// remboursement si l'utilisateur a payé pour cette commande
$amountPaid = $this->orderSolver->getAmount(Order::AMOUNT_PAID);

if ($amountPaid > 0.01) {
$this->creditHistoryBuilder->create(
CreditHistory::TYPE_REFUND,
$amountPaid,
GlobalParam::getCurrentProducer(),
$order->user,
$this->userSolver->getCurrent(),
$order
);
}

// delete
if ($this->producerRepository->getConfig('option_behavior_cancel_order') == Producer::BEHAVIOR_DELETE_ORDER_DELETE ||
($this->producerRepository->getConfig('option_behavior_cancel_order') == Producer::BEHAVIOR_DELETE_ORDER_STATUS && strlen($order->date_delete))
|| $force) {

$this->productOrderBuilder->deleteByOrder($order);

return $order->delete();
}
// status 'delete'
elseif ($this->producerRepository->getConfig('option_behavior_cancel_order') == Producer::BEHAVIOR_DELETE_ORDER_STATUS) {
$order->date_delete = date('Y-m-d H:i:s');

return $order->save();
}
}

/**
* Ajuste le crédit pour que la commande soit payée.
*/
public function processCredit(Order $order): void
{
if ($order->id_user) {
$paymentStatus = $this->orderSolver->getPaymentStatus($order);

if ($paymentStatus == Order::PAYMENT_PAID) {
return;
} elseif ($paymentStatus == Order::PAYMENT_SURPLUS) {
$type = CreditHistory::TYPE_REFUND;
$amount = $this->orderSolver->getAmount($order, Order::AMOUNT_SURPLUS);
} elseif ($paymentStatus == Order::PAYMENT_UNPAID) {
$type = CreditHistory::TYPE_PAYMENT;
$amount = $this->orderSolver->getAmount($order, Order::AMOUNT_REMAINING);
}

$this->creditHistoryBuilder->create(
$type,
$amount,
GlobalParam::getCurrentProducer(),
$order->user,
$this->userSolver->getCurrent(),
$order
);
}
}

// setTillerSynchronization
public function updateTillerSynchronization(Order $order)
{
$paymentStatus = $order->getPaymentStatus();

if ($paymentStatus == Order::PAYMENT_PAID) {
$order->tiller_synchronization = 1;
} else {
$order->tiller_synchronization = 0;
}

$order->save();

return $order;
}

/**
* Changement de statut d'une commande.
*/
public function changeOrderStatus(Order $order, string $newStatus, string $origin): void
{
$orderStatusArray = GlobalParam::get('orderStatus');
$userCurrent = $this->userSolver->getCurrent();

switch ($newStatus) {
case 'new-order' :
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
break;
case 'waiting-paiement-on-delivery':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
case 'waiting-paiement-by-credit':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
case 'paid-by-credit':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
case 'waiting-delevery' :
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
case 'delivered':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
case 'refunded':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
case 'cancel':
if (in_array($newStatus, $orderStatusArray[$order->status]['nextStatusAllow'])) {
$this->orderStatusHistoryBuilder->create($order, $userCurrent, $newStatus, $origin);
$order->status = $newStatus;
$order->save();
}
break;
default:
throw new NotFoundHttpException('Statut de commande inconnu.');
}
}

// initReference
public function generateReference(Order $order)
{
$idProducer = GlobalParam::getCurrentProducerId();
$producer = $this->producerRepository->getOneById($idProducer);

if (!$order->reference && $producer->option_order_reference_type == Producer::ORDER_REFERENCE_TYPE_YEARLY) {
$lastOrder = $this->orderRepository->getOneLastOfYear();

if ($lastOrder && $lastOrder->reference && strlen($lastOrder->reference) > 0) {
$pattern = '#A([0-9]+)C([0-9]+)#';
preg_match($pattern, $lastOrder->reference, $matches, PREG_OFFSET_CAPTURE);
$sizeNumReference = strlen($matches[2][0]);
$numReference = ((int)$matches[2][0]) + 1;
$numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT);

$order->reference = 'A' . $matches[1][0] . 'C' . $numReference;
} else {
$order->reference = 'A' . date('y') . 'C0001';
}

$order->save();
}
}

// initInvoicePrices
public function updateInvoicePrices(Order $order, $params = []): void
{
foreach ($order->productOrder as $productOrder) {
if ($productOrder->product) {
$this->productOrderBuilder->updateInvoicePrice($productOrder, $params);
}
}
}

}

+ 203
- 0
common/logic/Order/Order/OrderRepository.php Visa fil

@@ -4,10 +4,27 @@ namespace common\logic\Order\Order;

use common\logic\BaseService;
use common\logic\Distribution\Distribution\Distribution;
use common\logic\Order\ProductOrder\ProductOrder;
use common\logic\PointSale\PointSale\ProductOrderRepository;
use common\logic\Producer\Producer\Producer;
use common\logic\Producer\Producer\ProducerRepository;
use common\logic\Product\Product\Product;
use common\logic\RepositoryInterface;
use yii\helpers\Html;

class OrderRepository extends BaseService implements RepositoryInterface
{
protected ProductOrderRepository $productOrderRepository;
protected ProducerRepository $producerRepository;
protected OrderSolver $orderSolver;

public function __construct()
{
$this->productOrderRepository = $this->loadService(ProductOrderRepository::class);
$this->producerRepository = $this->loadService(ProducerRepository::class);
$this->orderSolver = $this->loadService(OrderSolver::class);
}

public function defaultOptionsSearch(): array
{
return [
@@ -24,6 +41,44 @@ class OrderRepository extends BaseService implements RepositoryInterface
];
}

public function getOneById(Order $order)
{
return Order::searchOne(['order.id' => $order->id]);;
}

/**
* Recherche et initialise des commandes.
*/
public function searchBy($params = [], $options = [])
{
$orders = Order::searchBy($params, $options);

/*
* Initialisation des commandes
*/

if (is_array($orders)) {
if (count($orders)) {
foreach ($orders as $order) {
if (is_a($order, 'common\logic\Order\Order\Order')) {
$order->init();
}
}
return $orders;
}
} else {
$order = $orders;
if (is_a($order, 'common\logic\Order\Order\Order')) {
return $order->init();
} // count
else {
return $order;
}
}

return false;
}

public function getByDistribution(Distribution $distribution, string $conditionAppend = '')
{
return Order::searchAll([
@@ -34,4 +89,152 @@ class OrderRepository extends BaseService implements RepositoryInterface
'conditions' => 'date_delete IS NULL ' . $conditionAppend
]);
}

/**
* Retourne les informations relatives à la commande au format JSON.
*/
public function getDataJson(Order $order): string
{
$jsonOrder = [];
if ($order) {
$jsonOrder = [
'products' => [],
'amount' => $order->amount,
'str_amount' => $order->getAmountWithTax(Order::AMOUNT_TOTAL, true),
'paid_amount' => $order->getAmount(Order::AMOUNT_PAID),
'comment' => $order->comment,
];

foreach ($order->productOrder as $productOrder) {
$jsonOrder['products'][$productOrder->id_product] = $productOrder->quantity;
}
}

return json_encode($jsonOrder);
}

/**
* Retourne le résumé du panier au format HTML.
*/
public function getCartSummary(Order $order, $htmlFormat = true): string
{
if (!isset($order->productOrder)) {
$order->productOrder = $this->productOrderRepository->getByOrder($order);
}

$html = '';
$i = 0;
$count = count($order->productOrder);
foreach ($order->productOrder as $p) {
if (isset($p->product)) {
$html .= Html::encode($p->product->name) . ' (' . $p->quantity . '&nbsp;' . 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();
}


}

+ 358
- 0
common/logic/Order/Order/OrderSolver.php Visa fil

@@ -2,10 +2,368 @@

namespace common\logic\Order\Order;

use common\helpers\GlobalParam;
use common\helpers\Price;
use common\logic\BaseService;
use common\logic\Document\Document\Document;
use common\logic\Document\Document\DocumentSolver;
use common\logic\Order\ProductOrder\ProductOrder;
use common\logic\Producer\Producer\Producer;
use common\logic\Product\Product\Product;
use common\logic\SolverInterface;
use yii\helpers\Html;

class OrderSolver extends BaseService implements SolverInterface
{
protected DocumentSolver $documentSolver;

public function __construct()
{
$this->documentSolver = $this->loadService(DocumentSolver::class);
}

public function getFieldNameAmount($typeTotal = Order::AMOUNT_TOTAL, $typeField = ''): string
{
$fieldName = 'amount';
if ($typeTotal == Order::INVOICE_AMOUNT_TOTAL) {
$fieldName = 'invoice_amount';
}

if ($typeField == 'vat') {
$fieldName = $fieldName . '_vat';
} elseif ($typeField == 'with_tax') {
$fieldName = $fieldName . '_with_tax';
}

return $fieldName;
}

public function getTotalVat(Order $order, $typeTotal = Order::AMOUNT_TOTAL): float
{
$fieldName = $this->getFieldNameAmount($typeTotal, 'vat');
$totalVat = 0;

foreach ($order->$fieldName as $vat) {
$totalVat += $vat;
}

return $totalVat;
}

/**
* Retourne le statut de paiement de la commande (payée, surplus, ou impayée).
*/
public function getPaymentStatus(Order $order): ?string
{
// payé
if ($this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) < 0.01 &&
$this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) > -0.01) {
return Order::PAYMENT_PAID;
} // à rembourser
elseif ($this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) <= -0.01) {
return Order::PAYMENT_SURPLUS;
} // reste à payer
elseif ($this->getAmountWithtax($order) - $this->getAmount($order, Order::AMOUNT_PAID) >= 0.01) {
return Order::PAYMENT_UNPAID;
}

return null;
}

/**
* Retourne le résumé du point de vente lié à la commande au format HTML.
*/
public function getPointSaleSummary(Order $order): string
{
$html = '';

if (isset($order->pointSale)) {
$html .= '<span class="name-point-sale">' .
Html::encode($order->pointSale->name) .
'</span>' .
'<br /><span class="locality">'
. Html::encode($order->pointSale->locality)
. '</span>';

if (strlen($order->comment_point_sale)) {
$html .= '<div class="comment"><span>'
. Html::encode($order->comment_point_sale)
. '</span></div>';
}
} else {
$html .= 'Point de vente supprimé';
}

return $html;
}

/**
* Retourne une chaine de caractère décrivant l'utilisateur lié à la commande.
*/
public function getStrUser(Order $order): string
{
if (isset($order->user)) {
if (isset($order->user->name_legal_person) && strlen($order->user->name_legal_person)) {
return Html::encode($order->user->name_legal_person);
} else {
$strUser = $order->user->lastname;
if ($order->user->lastname && $order->user->name) {
$strUser .= ' ' . $order->user->name;
}
return Html::encode($strUser);
}
} elseif (strlen($order->username)) {
return Html::encode($order->username);
} else {
return 'Client introuvable';
}
}

public function isLinkedToValidDocument(Order $order): bool
{
return ($order->deliveryNote && $this->documentSolver->isStatusValid($order->deliveryNote))
|| ($order->quotation && $this->documentSolver->isStatusValid($order->quotation))
|| ($order->invoice && $this->documentSolver->isStatusValid($order->invoice));
}

public function getCommentReport(Order $order): string
{
$comment = '';
$hasComment = false;

if ($order->comment && strlen($order->comment) > 0) {
$hasComment = true;
$comment .= $order->comment;
}

if ($order->delivery_home && $order->delivery_address && strlen($order->delivery_address) > 0) {
if ($hasComment) {
$comment .= '<br /><br />';
}

$comment .= '<strong>Livraison à domicile :</strong><br />';
$comment .= nl2br($order->delivery_address);
}

return $comment;
}

public function getUsername(Order $order): string
{
$username = '';
if ($order->user) {
$username = $order->user->getUsername();
}
if (strlen($order->username)) {
$username = $order->username;
}
return $username;
}

/**
* Retourne un bloc html présentant une date.
*/
public function getBlockDate(Order $order): string
{
return '<div class="block-date">
<div class="day">' . strftime('%A', strtotime($order->distribution->date)) . '</div>
<div class="num">' . date('d', strtotime($order->distribution->date)) . '</div>
<div class="month">' . strftime('%B', strtotime($order->distribution->date)) . '</div>
</div>';
}

/**
* Retourne le nombre de produits commandés.
*/
public function countProducts(Order $order)
{
if ($order->productOrder && is_array($order->productOrder)) {
return count($order->productOrder);
}

return 0;
}

public function getProductQuantityPieces(Product $product, array $orders): int
{
$quantity = 0;

if (isset($orders) && is_array($orders) && count($orders)) {
foreach ($orders as $c) {
if (is_null($c->date_delete)) {
foreach ($c->productOrder as $po) {
if ($po->id_product == $product->id) {
if ($po->unit == 'piece') {
$quantity += $po->quantity;
} else {
if (isset($po->product) && $po->product->weight > 0) {
$quantity += ($po->quantity * Product::$unitsArray[$po->unit]['coefficient']) / $po->product->weight;
}
}
}
}
}
}
}

return $quantity;
}

/**
* Retourne la quantité d'un produit donné de plusieurs commandes.
*/
public function getProductQuantity(Product $product, array $orders, $ignoreCancel = false, $unit = null): int
{
$quantity = 0;

if (isset($orders) && is_array($orders) && count($orders)) {
foreach ($orders as $c) {
if (is_null($c->date_delete) || $ignoreCancel) {
foreach ($c->productOrder as $po) {
if ($po->id_product == $product->id &&
((is_null($unit) && $po->product->unit == $po->unit) || (!is_null($unit) && strlen(
$unit
) && $po->unit == $unit))) {
$quantity += $po->quantity;
}
}
}
}
}

return $quantity;
}

/**
* Retourne une classe identifiant l'historique de la commande (ajoutée,
* modifiée, supprimée).
*/
public function getClassHistory(Order $order): string
{
if (!is_null($order->date_delete)) {
return 'commande-delete';
}

if (!is_null($order->date_update)) {
return 'commande-update';
}

return 'commande-create';
}

/**
* Retourne l'historique de la commande (ajoutée, modifiée, supprimée) au format HTML.
*/
public function getStrHistory(Order $order): string
{
$arr = [
'class' => 'create',
'glyphicon' => 'plus',
'str' => 'Ajoutée',
'date' => $order->date
];

if (!is_null($order->date_update)) {
$arr = [
'class' => 'update',
'glyphicon' => 'pencil',
'str' => 'Modifiée',
'date' => $order->date_update
];
}
if (!is_null($order->date_delete)) {
$arr = [
'class' => 'delete',
'glyphicon' => 'remove',
'str' => 'Annulée',
'date' => $order->date_delete
];
}

$html = '<div class="small"><span class="' . $arr['class'] . '">'
. '<span class="glyphicon glyphicon-' . $arr['glyphicon'] . '"></span> '
. $arr['str'] . '</span> le <strong>'
. date('d/m/Y à G\hi', strtotime($arr['date'])) . '</strong></div>';

return $html;
}

/**
* Retourne l'origine de la commande (client, automatique ou admin) sous forme texte ou HTML.
*/
public function getStrOrigin(Order $order, $withLabel = false): string
{
$classLabel = '';
$str = '';

if ($order->origin == Order::ORIGIN_USER) {
$classLabel = 'success';
$str = 'Client';
} elseif ($order->origin == Order::ORIGIN_AUTO) {
$classLabel = 'default';
$str = 'Auto';
} elseif ($order->origin == Order::ORIGIN_ADMIN) {
$classLabel = 'warning';
$str = 'Vous';
}

if ($withLabel) {
return '<span class="label label-' . $classLabel . '">'
. $str . '</span>';
} else {
return $str;
}
}

/**
* Retourne le montant de la commande (total, payé, restant, ou en surplus).
*/
public function getAmount(Order $order, string $type = Order::AMOUNT_TOTAL, $format = false)
{
$amount = $order->amount;
if ($type == Order::INVOICE_AMOUNT_TOTAL && $order->invoice_amount) {
$amount = $order->invoice_amount;
}

return $this->_getAmountGeneric($order, $type, $amount, $format);
}

public function getAmountWithTax(Order $order, string $type = Order::AMOUNT_TOTAL, $format = false)
{
$amount = $order->amount + $this->getTotalVat($order, $type);
if ($type == Order::INVOICE_AMOUNT_TOTAL && $order->invoice_amount) {
$amount = $order->invoice_amount + $this->getTotalVat($order, $type);
}

return $this->_getAmountGeneric($order, $type, $amount, $format);
}

protected function _getAmountGeneric(Order $order, string $type, float $amountOrder, bool $format)
{
switch ($type) {
case Order::AMOUNT_TOTAL :
case Order::INVOICE_AMOUNT_TOTAL :
$amount = $amountOrder;
break;
case Order::AMOUNT_PAID :
$amount = $order->paid_amount;
break;
case Order::AMOUNT_REMAINING :
$amount = $this->getAmountWithTax($order, Order::AMOUNT_TOTAL)
- $this->getAmountWithTax($order,Order::AMOUNT_PAID);
break;
case Order::AMOUNT_SURPLUS :
$amount = $this->getAmountWithTax($order,Order::AMOUNT_PAID)
- $this->getAmountWithTax($order,Order::AMOUNT_TOTAL);
break;
}

if ($format) {
return Price::format($amount);
} else {
return $amount;
}
}


}

+ 51
- 69
common/logic/Order/OrderStatusHistory/OrderStatusHistory.php Visa fil

@@ -3,78 +3,60 @@
namespace common\logic\Order\OrderStatusHistory;

use common\components\ActiveRecordCommon;
use common\logic\Order\Order\Order;
use common\logic\User\User\User;

/**
* This is the model class for table "order_order_status".
*
* @property integer $id
* @property integer $id_order
* @property integer $id_order_status
* @property string $date
* This is the model class for table "order_status_history".
*/
class OrderStatusHistory extends ActiveRecordCommon
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'order_status_history';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_order', 'status', 'id_user', 'date', 'origin'], 'required'],
[['id_order', 'id_user',], 'integer'],
[['date'], 'safe'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_order' => 'Commande',
'id_user' => 'Utilisateur',
'status' => 'Statut',
'origin' => 'Origine',
'date' => 'Date',
];
}

/*
* Relations
*/

public function getOrder()
{
return $this->hasOne( User::className(), ['id' => 'id_order']);
}

public function getUser()
{
return $this->hasOne( User::className(), ['id' => 'id_user']);
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => [],
'join_with' => ['order', 'orderStatus'],
'orderby' => 'date ASC',
'attribute_id_producer' => ''
];
}
/**
* @inheritdoc
*/
public static function tableName()
{
return 'order_status_history';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_order', 'status', 'id_user', 'date', 'origin'], 'required'],
[['id_order', 'id_user',], 'integer'],
[['date'], 'safe'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_order' => 'Commande',
'id_user' => 'Utilisateur',
'status' => 'Statut',
'origin' => 'Origine',
'date' => 'Date',
];
}

/*
* Relations
*/

public function getOrder()
{
return $this->hasOne(Order::class, ['id' => 'id_order']);
}

public function getUser()
{
return $this->hasOne(User::class, ['id' => 'id_user']);
}
}

+ 25
- 1
common/logic/Order/OrderStatusHistory/OrderStatusHistoryBuilder.php Visa fil

@@ -4,13 +4,37 @@ namespace common\logic\Order\OrderStatusHistory;

use common\logic\BaseService;
use common\logic\BuilderInterface;
use common\logic\Order\Order\Order;
use common\logic\User\User\User;
use common\logic\User\User\UserSolver;

class OrderStatusHistoryBuilder extends BaseService implements BuilderInterface
{
public function instanciate(): OrderStatusHistory
protected UserSolver $userSolver;

public function __construct()
{
$this->userSolver = $this->loadService(UserSolver::class);
}

public function instanciate(Order $order, User $user, string $status, string $origin): OrderStatusHistory
{
$orderStatusHistory = new OrderStatusHistory();

$orderStatusHistory->id_order = $order->id;
$orderStatusHistory->populateRelation('order', $order);
$orderStatusHistory->id_user = $user->id;
$orderStatusHistory->populateRelation('user', $user);
$orderStatusHistory->status = $status;
$orderStatusHistory->origin = $origin;
$orderStatusHistory->date = date('Y-m-d H:i:s');

return $orderStatusHistory;
}

public function create(Order $order, User $user, string $status, string $origin): OrderStatusHistory
{
$orderStatusHistory = $this->instanciate($order, $user, $status, $origin);
$orderStatusHistory->save();
}
}

+ 9
- 1
common/logic/Order/OrderStatusHistory/OrderStatusHistoryRepository.php Visa fil

@@ -7,5 +7,13 @@ use common\logic\RepositoryInterface;

class OrderStatusHistoryRepository extends BaseService implements RepositoryInterface
{

public function defaultOptionsSearch(): array
{
return [
'with' => [],
'join_with' => ['order', 'orderStatus'],
'orderby' => 'date ASC',
'attribute_id_producer' => ''
];
}
}

+ 73
- 109
common/logic/Order/ProductOrder/ProductOrder.php Visa fil

@@ -41,120 +41,84 @@ namespace common\logic\Order\ProductOrder;
use common\helpers\GlobalParam;
use common\helpers\Price;
use common\components\ActiveRecordCommon;
use common\logic\Config\TaxRate\TaxRate;
use common\logic\Product\Product\Product;

/**
* This is the model class for table "product_order".
*
* @property integer $id
* @property integer $id_order
* @property integer $id_product
* @property double $quantity
* @property string $unit
*/
class ProductOrder extends ActiveRecordCommon
{

/**
* @inheritdoc
*/
public static function tableName()
{
return 'product_order';
}

/*
* Relations
*/

public function getProduct()
{
return $this->hasOne( Product::className(), ['id' => 'id_product']);
}

public function getTaxRate()
{
return $this->hasOne(TaxRate::className(), ['id' => 'id_tax_rate']);
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_order', 'id_product', 'quantity'], 'required'],
[['id_order', 'id_product', 'id_tax_rate'], 'integer'],
[['unit'], 'string', 'max' => 255],
[['quantity'], 'number', 'min' => 0],
[['price', 'invoice_price'], 'double'],
[['description'], 'safe']
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_order' => 'Commande',
'id_product' => 'Product',
'quantity' => 'Quantité',
'unit' => 'Unité',
'id_tax_rate' => 'Taxe',
'description' => 'Description',
'price' => 'Prix',
'invoice_price' => 'Prix facturé',
];
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => ['taxRate'],
'join_with' => [],
'orderby' => '',
'attribute_id_producer' => ''
];
/**
* @inheritdoc
*/
public static function tableName()
{
return 'product_order';
}

/*
* Relations
*/

public function getProduct()
{
return $this->hasOne(Product::class, ['id' => 'id_product']);
}

public function getTaxRate()
{
return $this->hasOne(TaxRate::class, ['id' => 'id_tax_rate']);
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['id_order', 'id_product', 'quantity'], 'required'],
[['id_order', 'id_product', 'id_tax_rate'], 'integer'],
[['unit'], 'string', 'max' => 255],
[['quantity'], 'number', 'min' => 0],
[['price', 'invoice_price'], 'double'],
[['description'], 'safe']
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'id_order' => 'Commande',
'id_product' => 'Product',
'quantity' => 'Quantité',
'unit' => 'Unité',
'id_tax_rate' => 'Taxe',
'description' => 'Description',
'price' => 'Prix',
'invoice_price' => 'Prix facturé',
];
}

public function afterFind()
{
if ($this->taxRate == null) {
$this->populateRelation('taxRate', GlobalParam::getCurrentProducer()->taxRate);
}

public function afterFind() {
if ($this->taxRate == null) {
$this->populateRelation('taxRate', GlobalParam::getCurrentProducer()->taxRate);
}
parent::afterFind();
}

public function getPrice()
{
return $this->price ;
}

public function getInvoicePrice() {
return $this->invoice_price ;
}

/**
* Retourne le prix du produit avec taxe
*/
public function getPriceWithTax()
{
return Price::getPriceWithTax($this->price, $this->taxRate->value);
}

public function getPriceByTypeTotal($typeTotal = Order::AMOUNT_TOTAL)
{
if($typeTotal == Order::INVOICE_AMOUNT_TOTAL && $this->invoice_price) {
return $this->invoice_price;
}

return $this->price;
}

parent::afterFind();
}

public function getPrice()
{
return $this->price;
}

public function getInvoicePrice()
{
return $this->invoice_price;
}
}

+ 17
- 0
common/logic/Order/ProductOrder/ProductOrderBuilder.php Visa fil

@@ -4,6 +4,7 @@ namespace common\logic\Order\ProductOrder;

use common\logic\BaseService;
use common\logic\BuilderInterface;
use common\logic\Order\Order\Order;
use common\logic\PointSale\PointSale\PointSale;
use common\logic\Product\Product\ProductSolver;
use common\logic\User\User\User;
@@ -45,4 +46,20 @@ class ProductOrderBuilder extends BaseService implements BuilderInterface

return $productOrder;
}

public function updateInvoicePrice(ProductOrder $productOrder, array $params = []): void
{
$productOrder->invoice_price = $this->productSolver->getPrice($productOrder->product, [
'user' => isset($params['user']) ?? null,
'user_producer' => isset($params['user_producer']) ?? null,
'point_sale' => isset($params['point_sale']) ?? null,
'quantity' => $productOrder->quantity
]);
$productOrder->save();
}

public function deleteByOrder(Order $order): void
{
ProductOrder::deleteAll(['id_order' => $order->id]);
}
}

+ 15
- 0
common/logic/Order/ProductOrder/ProductOrderRepository.php Visa fil

@@ -3,9 +3,24 @@
namespace common\logic\PointSale\PointSale;

use common\logic\BaseService;
use common\logic\Order\Order\Order;
use common\logic\Order\ProductOrder\ProductOrder;
use common\logic\RepositoryInterface;

class ProductOrderRepository extends BaseService implements RepositoryInterface
{
public function defaultOptionsSearch(): array
{
return [
'with' => ['taxRate'],
'join_with' => [],
'orderby' => '',
'attribute_id_producer' => ''
];
}

public function getByOrder(Order $order)
{
return ProductOrder::find()->where(['id_order' => $order->id])->all()
}
}

+ 17
- 0
common/logic/Order/ProductOrder/ProductOrderSolver.php Visa fil

@@ -2,10 +2,27 @@

namespace common\logic\Order\ProductOrder;

use common\helpers\Price;
use common\logic\BaseService;
use common\logic\Order\Order\Order;
use common\logic\SolverInterface;

class ProductOrderSolver extends BaseService implements SolverInterface
{
/**
* Retourne le prix du produit avec taxe
*/
public function getPriceWithTax(ProductOrder $productOrder): float
{
return Price::getPriceWithTax($productOrder->price, $productOrder->taxRate->value);
}

public function getPriceByTypeTotal(ProductOrder $productOrder, string $typeTotal = Order::AMOUNT_TOTAL): float
{
if ($typeTotal == Order::INVOICE_AMOUNT_TOTAL && $productOrder->invoice_price) {
return $productOrder->invoice_price;
}

return $productOrder->price;
}
}

+ 278
- 335
common/logic/PointSale/PointSale/PointSale.php Visa fil

@@ -39,362 +39,305 @@
namespace common\logic\PointSale\PointSale;

use common\helpers\GlobalParam;
use common\logic\Distribution\PointSaleDistribution\PointSaleDistribution;
use common\logic\PointSale\UserPointSale\UserPointSale;
use common\logic\Producer\Producer\Producer;
use common\logic\User\User\User;
use yii\helpers\Html;
use common\components\ActiveRecordCommon;

/**
* This is the model class for table "point_vente".
*
* @property integer $id
* @property string $name
* @property string $address
* @property integer $id_producer
* @property integer $default
* This is the model class for table "point_sale".
*/
class PointSale extends ActiveRecordCommon
{
var $orders = [];
var $revenues = 0;
var $revenues_with_tax = 0;
var $data_select_orders;
var $data_options_orders;
var $users = [];
var $users_comment = [];

/**
* @inheritdoc
*/
public static function tableName()
{
return 'point_sale';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['name'], 'required'],
[['restricted_access'], 'boolean'],
[['name', 'code'], 'string', 'max' => 255],
[['address', 'locality', 'infos_monday', 'infos_tuesday',
'infos_wednesday', 'infos_thursday', 'infos_friday',
'infos_saturday', 'infos_sunday', 'credit_functioning', 'bread_box_code'], 'string'],
[['point_production', 'credit', 'delivery_monday', 'delivery_tuesday',
'delivery_wednesday', 'delivery_thursday', 'delivery_friday',
'delivery_saturday', 'delivery_sunday', 'default', 'is_bread_box'], 'boolean'],
['point_production', 'default', 'value' => 0],
[['id_producer', 'id_user', 'maximum_number_orders', 'status'], 'integer'],
['id_producer', 'required'],
[['users', 'users_comment', 'code'], 'safe'],
[['product_price_percent'], 'double'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Nom',
'address' => 'Adresse',
'locality' => 'Localité',
'point_production' => 'Point de production',
'infos_monday' => 'Lundi',
'infos_tuesday' => 'Mardi',
'infos_wednesday' => 'Mercredi',
'infos_thursday' => 'Jeudi',
'infos_friday' => 'Vendredi',
'infos_saturday' => 'Samedi',
'infos_sunday' => 'Dimanche',
'restricted_access' => 'Accès restreint',
'credit' => 'Activer le Crédit',
'delivery_monday' => 'Lundi',
'delivery_tuesday' => 'Mardi',
'delivery_wednesday' => 'Mercredi',
'delivery_thursday' => 'Jeudi',
'delivery_friday' => 'Vendredi',
'delivery_saturday' => 'Samedi',
'delivery_sunday' => 'Dimanche',
'code' => 'Code',
'credit_functioning' => 'Utilisation du Crédit par l\'utilisateur',
'default' => 'Point de vente par défaut',
'id_user' => 'Contact',
'product_price_percent' => 'Prix produits : pourcentage',
'maximum_number_orders' => 'Nombre maximum de commandes',
'is_bread_box' => 'Boîte à pain',
'bread_box_code' => 'Code boîte à pain',
'status' => 'Statut'
];
}

/*
* Relations
*/

public function getUserPointSale()
{
return $this->hasMany(
UserPointSale::className(),
['id_point_sale' => 'id']
);
}

public function getPointSaleDistribution()
{
return $this->hasMany(
PointSaleDistributionModel::className(),
['id_point_sale' => 'id']
);
}

public function getUser()
{
return $this->hasOne(
User::className(),
['id' => 'id_user']
) ;
}

/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
{
return [
'with' => [],
'join_with' => [],
'orderby' => 'is_bread_box ASC, name ASC',
'attribute_id_producer' => 'point_sale.id_producer'
];
var $orders = [];
var $revenues = 0;
var $revenues_with_tax = 0;
var $data_select_orders;
var $data_options_orders;
var $users = [];
var $users_comment = [];

/**
* @inheritdoc
*/
public static function tableName()
{
return 'point_sale';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['name'], 'required'],
[['restricted_access'], 'boolean'],
[['name', 'code'], 'string', 'max' => 255],
[['address', 'locality', 'infos_monday', 'infos_tuesday',
'infos_wednesday', 'infos_thursday', 'infos_friday',
'infos_saturday', 'infos_sunday', 'credit_functioning', 'bread_box_code'], 'string'],
[['point_production', 'credit', 'delivery_monday', 'delivery_tuesday',
'delivery_wednesday', 'delivery_thursday', 'delivery_friday',
'delivery_saturday', 'delivery_sunday', 'default', 'is_bread_box'], 'boolean'],
['point_production', 'default', 'value' => 0],
[['id_producer', 'id_user', 'maximum_number_orders', 'status'], 'integer'],
['id_producer', 'required'],
[['users', 'users_comment', 'code'], 'safe'],
[['product_price_percent'], 'double'],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Nom',
'address' => 'Adresse',
'locality' => 'Localité',
'point_production' => 'Point de production',
'infos_monday' => 'Lundi',
'infos_tuesday' => 'Mardi',
'infos_wednesday' => 'Mercredi',
'infos_thursday' => 'Jeudi',
'infos_friday' => 'Vendredi',
'infos_saturday' => 'Samedi',
'infos_sunday' => 'Dimanche',
'restricted_access' => 'Accès restreint',
'credit' => 'Activer le Crédit',
'delivery_monday' => 'Lundi',
'delivery_tuesday' => 'Mardi',
'delivery_wednesday' => 'Mercredi',
'delivery_thursday' => 'Jeudi',
'delivery_friday' => 'Vendredi',
'delivery_saturday' => 'Samedi',
'delivery_sunday' => 'Dimanche',
'code' => 'Code',
'credit_functioning' => 'Utilisation du Crédit par l\'utilisateur',
'default' => 'Point de vente par défaut',
'id_user' => 'Contact',
'product_price_percent' => 'Prix produits : pourcentage',
'maximum_number_orders' => 'Nombre maximum de commandes',
'is_bread_box' => 'Boîte à pain',
'bread_box_code' => 'Code boîte à pain',
'status' => 'Statut'
];
}

/*
* Relations
*/

public function getUserPointSale()
{
return $this->hasMany(
UserPointSale::class,
['id_point_sale' => 'id']
);
}

public function getPointSaleDistribution()
{
return $this->hasMany(
PointSaleDistribution::class,
['id_point_sale' => 'id']
);
}

public function getUser()
{
return $this->hasOne(
User::class,
['id' => 'id_user']
);
}

/**
* Enregistre le point de vente.
*/
public function save(bool $runValidation = true, array $attributeNames = NULL)
{
$this->id_producer = GlobalParam::getCurrentProducerId();
return parent::save($runValidation, $attributeNames);
}

/**
* Traite la mise à jour de l'attribut 'point_production'.
*/
public function processPointProduction()
{
if ($this->point_production) {
PointSale::updateAll(
['point_production' => 0],
['id_producer' => $this->id_producer]
);
$this->point_production = 1;
$this->save();
}

/**
* Initialise les commandes liées au point de vente.
*
* @param array $ordersArray
*/
public function initOrders($ordersArray)
{
$this->orders = [];
$this->revenues = 0;
$this->revenues_with_tax = 0;

if ($ordersArray) {
foreach ($ordersArray as $order) {
if ($this->id == $order->id_point_sale) {
$this->orders[] = $order;

if (is_null($order->date_delete)) {
$this->revenues += (float)$order->amount;
$this->revenues_with_tax += (float)$order->amount_with_tax;
}
}
}
}

/**
* Traite les accès restreints d'un point de vente.
*/
public function processRestrictedAccess()
{
UserPointSale::deleteAll(['id_point_sale' => $this->id]);

if (is_array($this->users) && count($this->users)) {
foreach ($this->users as $key => $val) {
$user = User::findOne($val);
if ($user) {
$userPointSale = new UserPointSale;
$userPointSale->id_user = $val;
$userPointSale->id_point_sale = $this->id;
if (isset($this->users_comment[$val]) && strlen($this->users_comment[$val])) {
$userPointSale->comment = $this->users_comment[$val];
}
$userPointSale->save();
}
}
}

/**
* Retourne les commandes liées à ce point de vente.
*
* @return array
*/
public function getOrders()
{
return $this->orders;
}

/**
* Enregistre le point de vente.
*
* @param boolean $runValidation
* @param array $attributeNames
* @return type
*/
public function save($runValidation = true, $attributeNames = NULL)
{
$this->id_producer = GlobalParam::getCurrentProducerId();
return parent::save($runValidation, $attributeNames);
}

/**
* Traite la mise à jour de l'attribut 'point_production'.
*/
public function processPointProduction()
{
if ($this->point_production) {
PointSale::updateAll(
['point_production' => 0],
['id_producer' => $this->id_producer]
);
$this->point_production = 1;
$this->save();
}

/**
* Retourne le commentaire de l'utilisateur courant lié au point de vente.
*
* @return string|null
*/
public function getComment()
{
if (isset($this->userPointSale)) {
foreach ($this->userPointSale as $userPointSale) {
if ($userPointSale->id_user == User::getCurrentId()) {
return $userPointSale->comment;
}
}
}

/**
* Traite les accès restreints d'un point de vente.
*/
public function processRestrictedAccess()
{
UserPointSale::deleteAll(['id_point_sale' => $this->id]);

if (is_array($this->users) && count($this->users)) {
foreach ($this->users as $key => $val) {
$user = User::findOne($val);
if ($user) {
$userPointSale = new UserPointSale;
$userPointSale->id_user = $val;
$userPointSale->id_point_sale = $this->id;
if (isset($this->users_comment[$val]) && strlen($this->users_comment[$val])) {
$userPointSale->comment = $this->users_comment[$val];
}
$userPointSale->save();
}
}
}
}

/**
* Retourne le commentaire de l'utilisateur courant lié au point de vente.
*
* @return string|null
*/
public function getComment()
{
if (isset($this->userPointSale)) {
foreach ($this->userPointSale as $userPointSale) {
if ($userPointSale->id_user == User::getCurrentId()) {
return $userPointSale->comment;
}
}
}
return null;
}

/**
* Retourne le nombre de points de vente pour l'établissement courant.
*
* @return integer
*/
public static function count()
{
return self::searchCount(['id_producer' => GlobalParam::getCurrentProducerId()]);
}

/**
* Vérifie le code d'accès à un point de vente.
*
* @param string $code
* @return boolean
*/
public function validateCode($code)
{
if (strlen($this->code)) {
if (trim(strtolower($code)) == trim(strtolower($this->code))) {
return true;
} else {
return false;
}
}

return null;
}

/**
* Retourne le nombre de points de vente pour l'établissement courant.
*
* @return integer
*/
public static function count()
{
return self::searchCount(['id_producer' => GlobalParam::getCurrentProducerId()]);
}

/**
* Vérifie le code d'accès à un point de vente.
*
* @param string $code
* @return boolean
*/
public function validateCode($code)
{
if (strlen($this->code)) {
if (trim(strtolower($code)) == trim(strtolower($this->code))) {
return true;
} else {
return false;
}
}

/**
* Retourne les jours de livraison du point de vente sous forme d'une chaine
* de caractères.
*
* @return string
*/
public function getStrDeliveryDays()
{
$str = '';

if ($this->delivery_monday) $str .= 'lundi, ';
if ($this->delivery_tuesday) $str .= 'mardi, ';
if ($this->delivery_wednesday) $str .= 'mercredi, ';
if ($this->delivery_thursday) $str .= 'jeudi, ';
if ($this->delivery_friday) $str .= 'vendredi, ';
if ($this->delivery_saturday) $str .= 'samedi, ';
if ($this->delivery_sunday) $str .= 'dimanche, ';

if (strlen($str)) {
return substr($str, 0, strlen($str) - 2);
} else {
return '';
}
return true;
}

/**
* Retourne les jours de livraison du point de vente sous forme d'une chaine
* de caractères.
*
* @return string
*/
public function getStrDeliveryDays()
{
$str = '';

if ($this->delivery_monday) $str .= 'lundi, ';
if ($this->delivery_tuesday) $str .= 'mardi, ';
if ($this->delivery_wednesday) $str .= 'mercredi, ';
if ($this->delivery_thursday) $str .= 'jeudi, ';
if ($this->delivery_friday) $str .= 'vendredi, ';
if ($this->delivery_saturday) $str .= 'samedi, ';
if ($this->delivery_sunday) $str .= 'dimanche, ';

if (strlen($str)) {
return substr($str, 0, strlen($str) - 2);
} else {
return '';
}

/**
* Retourne un commentaire informant l'utilisateur sur les détails de
* livraison d'un point de vente et pour un jour donné.
*
* @param string $jour
* @return string
*/
public function getStrInfos($day)
{
$str = '';
$field = 'infos_' . $day;

if (strlen($this->$field)) {
$str = nl2br(Html::encode($this->$field));
$str = preg_replace('/\[select_previous_day\](.*?)\[\/select_previous_day\]/', '<a href="javascript:void(0);" class="select-previous-day">$1</a>', $str);
}
return $str;
}

/**
* Retourne un commentaire informant l'utilisateur sur les détails de
* livraison d'un point de vente et pour un jour donné.
*
* @param string $jour
* @return string
*/
public function getStrInfos($day)
{
$str = '';
$field = 'infos_' . $day;

if (strlen($this->$field)) {
$str = nl2br(Html::encode($this->$field));
$str = preg_replace('/\[select_previous_day\](.*?)\[\/select_previous_day\]/', '<a href="javascript:void(0);" class="select-previous-day">$1</a>', $str);
}

/**
* Retourne le mode de fonctionnement du crédit du point de vente.
*
* @return string
*/
public function getCreditFunctioning()
{
return strlen($this->credit_functioning) > 0 ?
$this->credit_functioning :
Producer::getConfig('credit_functioning');
return $str;
}

/**
* Retourne le mode de fonctionnement du crédit du point de vente.
*
* @return string
*/
public function getCreditFunctioning()
{
return strlen($this->credit_functioning) > 0 ?
$this->credit_functioning :
Producer::getConfig('credit_functioning');
}

/**
* Lie un utilisateur au point de vente.
*
* @param integer $idUser
*/
public function linkUser($idUser)
{
if ($idUser) {
$userPointSale = UserPointSale::find()
->where([
'id_user' => $idUser,
'id_point_sale' => $this->id
])->one();

if (!$userPointSale) {
$userPointSale = new UserPointSale;
$userPointSale->id_user = $idUser;
$userPointSale->id_point_sale = $this->id;
$userPointSale->save();
}
}
}

/**
* Lie un utilisateur au point de vente.
*
* @param integer $idUser
*/
public function linkUser($idUser)
{
if ($idUser) {
$userPointSale = UserPointSale::find()
->where([
'id_user' => $idUser,
'id_point_sale' => $this->id
])->one();
public static function populateDropdownList()
{
$pointSalesArrayDropdown = ['' => '--'];
$pointSalesArray = PointSale::find()->where('id_producer = ' . GlobalParam::getCurrentProducerId())->all();

if (!$userPointSale) {
$userPointSale = new UserPointSale;
$userPointSale->id_user = $idUser;
$userPointSale->id_point_sale = $this->id;
$userPointSale->save();
}
}
foreach ($pointSalesArray as $pointSale) {
$pointSalesArrayDropdown[$pointSale['id']] = $pointSale['name'];
}

public static function populateDropdownList()
{
$pointSalesArrayDropdown = ['' => '--'] ;
$pointSalesArray = PointSale::find()->where('id_producer = ' . GlobalParam::getCurrentProducerId())->all() ;

foreach($pointSalesArray as $pointSale) {
$pointSalesArrayDropdown[$pointSale['id']] = $pointSale['name'] ;
}

return $pointSalesArrayDropdown ;
}
return $pointSalesArrayDropdown;
}
}

+ 24
- 0
common/logic/PointSale/PointSale/PointSaleBuilder.php Visa fil

@@ -4,6 +4,7 @@ namespace common\logic\PointSale\PointSale;

use common\logic\BaseService;
use common\logic\BuilderInterface;
use common\logic\Order\Order\Order;
use common\logic\SolverInterface;

class PointSaleBuilder extends BaseService implements BuilderInterface
@@ -14,4 +15,27 @@ class PointSaleBuilder extends BaseService implements BuilderInterface

return $pointSale;
}

/**
* Initialise les commandes liées au point de vente.
*/
public function initOrders(PointSale $pointSale, array $ordersArray): void
{
$pointSale->orders = [];
$pointSale->revenues = 0;
$pointSale->revenues_with_tax = 0;

if ($ordersArray) {
foreach ($ordersArray as $order) {
if ($pointSale->id == $order->id_point_sale) {
$pointSale->orders[] = $order;

if (is_null($order->date_delete)) {
$pointSale->revenues += (float) $order->amount;
$pointSale->revenues_with_tax += (float) $order->amount_with_tax;
}
}
}
}
}
}

+ 11
- 1
common/logic/PointSale/PointSale/PointSaleRepository.php Visa fil

@@ -10,10 +10,20 @@ use common\logic\RepositoryInterface;

class PointSaleRepository extends BaseService implements RepositoryInterface
{
public function defaultOptionsSearch(): array
{
return [
'with' => [],
'join_with' => [],
'orderby' => 'is_bread_box ASC, name ASC',
'attribute_id_producer' => 'point_sale.id_producer'
];
}

public function getByDistribution(Distribution $distribution)
{
return PointSale::find()
->with(['pointSaleDistribution' => function($q) use ($distribution) {
->with(['pointSaleDistribution' => function ($q) use ($distribution) {
$q->where(['id_distribution' => $distribution->id]);
}])
->where([

+ 0
- 1
common/logic/PointSale/UserPointSale/UserPointSale.php Visa fil

@@ -97,5 +97,4 @@ class UserPointSale extends ActiveRecordCommon
'attribute_id_producer' => ''
] ;
}

}

+ 8
- 0
common/logic/Producer/Producer/ProducerRepository.php Visa fil

@@ -6,6 +6,7 @@ use common\helpers\Departments;
use common\helpers\GlobalParam;
use common\helpers\Price;
use common\logic\BaseService;
use common\logic\Document\Document\DocumentInterface;
use common\logic\Producer\ProducerPriceRange\ProducerPriceRange;
use common\logic\Producer\ProducerPriceRange\ProducerPriceRangeRepository;
use common\logic\RepositoryInterface;
@@ -248,4 +249,11 @@ class ProducerRepository extends BaseService implements RepositoryInterface
$producer = $this->getOneById($user->id_producer);
return $producer->getName();
}

public function isDocumentDisplayOrders(DocumentInterface $document): bool
{
return ($document->getClass() == 'Invoice') ?
$this->getConfig('document_display_orders_invoice') :
$this->getConfig('document_display_orders_delivery_note');
}
}

+ 26
- 6
common/logic/User/CreditHistory/CreditHistoryBuilder.php Visa fil

@@ -4,6 +4,9 @@ namespace common\logic\User\CreditHistory;

use common\logic\BaseService;
use common\logic\BuilderInterface;
use common\logic\Order\Order\Order;
use common\logic\Producer\Producer\Producer;
use common\logic\User\User\User;
use common\logic\User\UserProducer\UserProducerBuilder;

class CreditHistoryBuilder extends BaseService implements BuilderInterface
@@ -17,19 +20,36 @@ class CreditHistoryBuilder extends BaseService implements BuilderInterface
$this->userProducerBuilder = $this->loadService(UserProducerBuilder::class);
}

public function instanciate(): CreditHistory
public function instanciate(string $type, float $amount, Producer $producer, User $user, User $userAction, Order $order = null): CreditHistory
{
$creditHistory = new CreditHistory();
$creditHistory = new CreditHistory;

$creditHistory->type = $type;
$creditHistory->amount = round($amount, 2);
$creditHistory->id_producer = $producer->id;
$creditHistory->populateRelation('producer', $producer);
$creditHistory->id_user = $user->id;
$creditHistory->populateRelation('user', $user);
$creditHistory->id_user_action = $userAction->id;
$creditHistory->populateRelation('userAction', $userAction);

if($order) {
$creditHistory->id_order = $order->id;
$creditHistory->populateRelation('order', $order);
}

return $creditHistory;
}

public function save(CreditHistory $creditHistory): bool
// saveCreditHistory
public function create(string $type, float $amount, Producer $producer, User $user, User $userAction, Order $order = null): ?CreditHistory
{
if ($creditHistory->getAmount() > -0.01 && $creditHistory->getAmount() < 0.01) {
return false;
if ($amount > -0.01 && $amount < 0.01) {
return null;
}

$creditHistory = $this->instanciate($type, $amount, $producer, $user, $userAction, $order);

// Initialisation du commentaire avant sauvegarde
$creditHistory->setComment($creditHistory->getComment() . $this->creditHistorySolver->getStrComment($creditHistory));

@@ -38,6 +58,6 @@ class CreditHistoryBuilder extends BaseService implements BuilderInterface
// Mise à jour du crédit au niveau de UserProducer
$this->userProducerBuilder->updateCredit($creditHistory);

return true;
return $creditHistory;
}
}

+ 9
- 6
common/logic/User/CreditHistory/CreditHistoryRepository.php Visa fil

@@ -3,16 +3,12 @@
namespace common\logic\User\CreditHistory;

use common\logic\BaseService;
use common\logic\Order\Order\Order;
use common\logic\RepositoryInterface;

class CreditHistoryRepository extends BaseService implements RepositoryInterface
{
/**
* Retourne les options de base nécessaires à la fonction de recherche.
*
* @return array
*/
public static function defaultOptionsSearch()
public function defaultOptionsSearch(): array
{
return [
'with' => [],
@@ -21,4 +17,11 @@ class CreditHistoryRepository extends BaseService implements RepositoryInterface
'attribute_id_producer' => CreditHistory::tableName() . '.id_producer'
];
}

public function getByOrder(Order $order)
{
return CreditHistory::find()
->where(['id_order' => $order->id])
->all();
}
}

+ 2
- 2
common/logic/User/CreditHistory/CreditHistorySolver.php Visa fil

@@ -58,8 +58,8 @@ class CreditHistorySolver implements SolverInterface

if (CreditHistory::TYPE_PAYMENT == $type || CreditHistory::TYPE_REFUND == $type) {
$order = $creditHistory->getOrderObject();
if ($order && $order->getDistributionOject()) {
$str .= '<br />Commande : ' . date('d/m/Y', strtotime($order->getDistributionOject()->getDate()));
if ($order && $order->distribution) {
$str .= '<br />Commande : ' . date('d/m/Y', strtotime($order->distribution->date));
} else {
$str .= '<br />Commande supprimée';
}

Laddar…
Avbryt
Spara