Browse Source

Merge branch 'develop'

master
Guillaume Bourgeois 10 months ago
parent
commit
50f96602b6
34 changed files with 407 additions and 63 deletions
  1. +53
    -0
      backend/controllers/ProducerInvoiceController.php
  2. +1
    -1
      backend/controllers/SubscriptionController.php
  3. +0
    -7
      backend/views/distribution/index.php
  4. +1
    -1
      backend/views/distribution/shopping-cart-labels.php
  5. +2
    -1
      backend/views/document/download.php
  6. +7
    -0
      backend/views/layouts/left.php
  7. +82
    -0
      backend/views/producer-invoice/index.php
  8. +2
    -4
      backend/views/producer/update.php
  9. +32
    -2
      common/components/DolibarrApi.php
  10. +3
    -1
      common/config/main.php
  11. +1
    -1
      common/config/params.php
  12. +6
    -0
      common/controllers/CommonController.php
  13. +5
    -1
      common/logic/Distribution/Distribution/Export/DistributionReportPdfGenerator.php
  14. +1
    -1
      common/logic/Distribution/Distribution/Export/DistributionReportTotalProductCsvGenerator.php
  15. +13
    -10
      common/logic/Distribution/Distribution/Export/DistributionShoppingCartLabelsPdfGenerator.php
  16. +30
    -0
      common/logic/Document/DeliveryNote/Event/DeliveryNoteObserver.php
  17. +2
    -0
      common/logic/Document/DeliveryNote/Service/DeliveryNoteBuilder.php
  18. +1
    -0
      common/logic/Document/Document/Service/DocumentManager.php
  19. +9
    -8
      common/logic/Order/Order/Repository/OrderRepository.php
  20. +24
    -0
      common/logic/Order/Order/Service/OrderSolver.php
  21. +8
    -0
      common/logic/PointSale/PointSale/Repository/PointSaleRepository.php
  22. +9
    -0
      common/logic/PointSale/PointSale/Repository/PointSaleRepositoryQuery.php
  23. +3
    -1
      common/logic/Producer/Producer/Model/Producer.php
  24. +10
    -0
      common/logic/Producer/Producer/Service/DolibarrProducerUtils.php
  25. +8
    -4
      common/logic/Product/Product/Repository/ProductRepository.php
  26. +3
    -3
      common/versions/23.11.C.php
  27. +28
    -0
      common/versions/23.12.A.php
  28. +11
    -0
      common/web/css/screen.css
  29. +10
    -0
      common/web/sass/_common.scss
  30. +26
    -0
      console/migrations/m231130_082147_add_column_producer_delivery_note_automatic_validation.php
  31. +2
    -6
      producer/controllers/CreditController.php
  32. +2
    -2
      producer/controllers/SubscriptionController.php
  33. +2
    -3
      producer/views/order/order.php
  34. +10
    -6
      producer/web/js/vuejs/order-order.js

+ 53
- 0
backend/controllers/ProducerInvoiceController.php View File

<?php

namespace backend\controllers;

use yii\filters\AccessControl;

class ProducerInvoiceController extends BackendController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'allow' => true,
'roles' => ['@'],
'matchCallback' => function ($rule, $action) {
return
$this->getParameterBag()->get('dolibarrApiKey')
&& $this->getUserModule()
->getAuthorizationChecker()
->isGrantedAsProducer($this->getUserCurrent());
}
],
],
],
];
}

public function actionIndex()
{
return $this->render('index', [
'invoicesArray' => $this->getProducerModule()
->getDolibarrUtils()
->getDolibarrProducerInvoices($this->getProducerCurrent())
]);
}

public function actionDownload(int $idDolibarrInvoice)
{
$documentDownload = \Yii::$app->dolibarrApi->downloadInvoice($idDolibarrInvoice);
if($documentDownload) {
return \Yii::$app->response->sendContentAsFile(base64_decode($documentDownload['content']), $documentDownload['filename'], [
'mimeType' => $documentDownload['content-type']
]);
}
else {
$this->addFlash('error', 'Facture introuvable');
return $this->redirectReferer();
}
}
}

+ 1
- 1
backend/controllers/SubscriptionController.php View File

$subscriptionModule = $this->getSubscriptionModule(); $subscriptionModule = $this->getSubscriptionModule();
$distributionModule = $this-> getDistributionModule(); $distributionModule = $this-> getDistributionModule();
$subscription = $subscriptionModule->findOneSubscriptionById($idSubscription); $subscription = $subscriptionModule->findOneSubscriptionById($idSubscription);
$matchedDistributionsArray = $distributionModule->findDistributionsIncomingMatchWithSubscrtiption($subscription);
$matchedDistributionsArray = $distributionModule->findDistributionsIncomingMatchWithSubscrtiption($subscription, true);


if ($generate) { if ($generate) {
if ($update) { if ($update) {

+ 0
- 7
backend/views/distribution/index.php View File

<order-state-payment :order="order" :producer="producer"></order-state-payment> <order-state-payment :order="order" :producer="producer"></order-state-payment>
</a> </a>
<span class="glyphicon glyphicon-time" title="Débit automatique du crédit la veille de la distribution" v-if="order.amount != 0 && order.isCreditAutoPayment && (order.amount_paid == 0 || order.amount_paid < order.amount)"></span> <span class="glyphicon glyphicon-time" title="Débit automatique du crédit la veille de la distribution" v-if="order.amount != 0 && order.isCreditAutoPayment && (order.amount_paid == 0 || order.amount_paid < order.amount)"></span>

<div v-if="order.amount_paid > 0 && order.amount_paid < order.amount">
<span class="glyphicon glyphicon-alert"></span> Reste à payer
</div>
<div v-if="order.amount_paid > order.amount">
<span class="glyphicon glyphicon-alert"></span> Surplus à rembourser
</div>
</template> </template>
</td> </td>
<td class="column-credit" v-if="!idActivePointSale || (pointSaleActive && pointSaleActive.credit == 1)"> <td class="column-credit" v-if="!idActivePointSale || (pointSaleActive && pointSaleActive.credit == 1)">

+ 1
- 1
backend/views/distribution/shopping-cart-labels.php View File

foreach($ordersArray as $key => $order) { foreach($ordersArray as $key => $order) {
$index ++; $index ++;


echo $distributionShoppingCartLabelsPdfGenerator->getShoppingCartLabelAsHtml($order);
echo $distributionShoppingCartLabelsPdfGenerator->getShoppingCartLabelAsHtml($order, $index);


if($index == $shoppingCartLabelsPerColumn) { if($index == $shoppingCartLabelsPerColumn) {
$index = 0; $index = 0;

+ 2
- 1
backend/views/document/download.php View File

$documentModule = $this->getDocumentModule(); $documentModule = $this->getDocumentModule();
$orderModule = $this->getOrderModule(); $orderModule = $this->getOrderModule();


$displayPrices = Yii::$app->controller->getClass() != 'DeliveryNote' || (Yii::$app->controller->getClass() == 'DeliveryNote' && $producerModule->getConfig('document_display_prices_delivery_note'));
$isDocumentDeliveryNote = $documentModule->getSolver()->isDocumentDeliveryNote($document);
$displayPrices = !$isDocumentDeliveryNote || ($isDocumentDeliveryNote && $producerModule->getConfig('document_display_prices_delivery_note'));
$displayProductDescription = $producerModule->getConfig('document_display_product_description'); $displayProductDescription = $producerModule->getConfig('document_display_product_description');
$documentPriceDecimals = (int) $producerModule->getConfig('option_document_price_decimals'); $documentPriceDecimals = (int) $producerModule->getConfig('option_document_price_decimals');



+ 7
- 0
backend/views/layouts/left.php View File

['label' => 'Paramètres', 'icon' => 'cog', 'url' => ['/producer/update'], 'visible' => $isUserCurrentGrantedAsProducer], ['label' => 'Paramètres', 'icon' => 'cog', 'url' => ['/producer/update'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => 'Accès', 'icon' => 'lock', 'url' => ['/access/index'], 'visible' => $isUserCurrentGrantedAsProducer], ['label' => 'Accès', 'icon' => 'lock', 'url' => ['/access/index'], 'visible' => $isUserCurrentGrantedAsProducer],
['label' => "Opendistrib", 'options' => ['class' => 'header'], 'visible' => $isUserCurrentGrantedAsProducer], ['label' => "Opendistrib", 'options' => ['class' => 'header'], 'visible' => $isUserCurrentGrantedAsProducer],
[
'label' => 'Mes factures',
'icon' => 'clone',
'url' => ['/producer-invoice/index'],
'visible' => $isUserCurrentGrantedAsProducer && Yii::$app->parameterBag->get('dolibarrApiKey'),
'active' => Yii::$app->controller->id == 'producer-invoice',
],
[ [
'label' => 'Développement', 'label' => 'Développement',
'icon' => 'code', 'icon' => 'code',

+ 82
- 0
backend/views/producer-invoice/index.php View File

<?php

/**
Copyright La boîte à pain (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.
*/

use common\helpers\Price;
use yii\helpers\Html;

$this->setTitle('Mes factures') ;
$this->addBreadcrumb($this->getTitle()) ;

?>

<?php if($invoicesArray && count($invoicesArray)): ?>
<div class="callout callout-info">
<span class="glyphicon glyphicon-info-sign"></span> Les factures et les réglements sont saisis en début de mois.
</div>

<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Montant</th>
<th>Statut</th>
<th>Téléchargement</th>
</tr>
</thead>
<tbody>
<?php foreach($invoicesArray as $invoice): ?>
<tr>
<td><?= date('d/m/Y', $invoice['date']); ?></td>
<td><?= Html::encode($invoice['ref']); ?></td>
<td><?= Price::format($invoice['total_ttc']); ?></td>
<td><?= ($invoice['remaintopay'] > 0) ? '<span class="label label-warning">Impayée</span>' : '<span class="label label-success">Payée</span>'; ?></td>
<td>
<a class="btn btn-default" href="<?= $this->getUrlManagerBackend()->createUrl(['producer-invoice/download', 'idDolibarrInvoice' => $invoice['id']]); ?>">
<span class="glyphicon glyphicon-download-alt"></span> Télécharger
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<div class="callout callout-info">
<span class="glyphicon glyphicon-info-sign"></span> Vous n'avez encore aucune facture.
</div>
<?php endif; ?>

+ 2
- 4
backend/views/producer/update.php View File

<?= $form->field($model, 'document_invoice_first_reference'); ?> <?= $form->field($model, 'document_invoice_first_reference'); ?>
<?= $form->field($model, 'document_delivery_note_prefix')->hint($hintKeywordsPrefix);; ?> <?= $form->field($model, 'document_delivery_note_prefix')->hint($hintKeywordsPrefix);; ?>
<?= $form->field($model, 'document_delivery_note_first_reference'); ?> <?= $form->field($model, 'document_delivery_note_first_reference'); ?>
<?= $form->field($model, 'option_invoice_only_based_on_delivery_notes')->dropDownList([
0 => 'Non',
1 => 'Oui'
]); ?>
<?= $form->field($model, 'delivery_note_automatic_validation')->dropDownList(Dropdown::noYesChoices()); ?>
<?= $form->field($model, 'option_invoice_only_based_on_delivery_notes')->dropDownList(Dropdown::noYesChoices()); ?>
<?= $form->field($model, 'option_document_width_logo') <?= $form->field($model, 'option_document_width_logo')
->dropDownList(Dropdown::numberChoices(50, 250, true, 'px', 50)); ?> ->dropDownList(Dropdown::numberChoices(50, 250, true, 'px', 50)); ?>
<?= $form->field($model, 'document_display_orders_invoice')->dropDownList(Dropdown::noYesChoices()); ?> <?= $form->field($model, 'document_display_orders_invoice')->dropDownList(Dropdown::noYesChoices()); ?>

+ 32
- 2
common/components/DolibarrApi.php View File



namespace common\components; namespace common\components;


use Psr\Http\Message\ResponseInterface;

class DolibarrApi extends AbstractApi class DolibarrApi extends AbstractApi
{ {
const RESOURCE_INVOICES = 'invoices'; const RESOURCE_INVOICES = 'invoices';
const RESOURCE_PRODUCTS = 'products'; const RESOURCE_PRODUCTS = 'products';
const RESOURCE_DOCUMENTS = 'documents'; const RESOURCE_DOCUMENTS = 'documents';


public function getInvoicesByThirParty(int $idThirdParty)
{
return $this->get(self::RESOURCE_INVOICES, [
'sortfield' => 't.rowid',
'sortorder' => 'DESC',
'thirdparty_ids' => $idThirdParty,
'limit' => 24
]);
}

public function getInvoice(int $idInvoice)
{
return $this->get(self::RESOURCE_INVOICES.'/'.$idInvoice, [
'contact_list' => 1
]);
}

public function downloadInvoice(string $idInvoice)
{
$invoice = $this->getInvoice($idInvoice);
if($invoice && isset($invoice['last_main_doc'])) {
$originalFilename = str_replace('facture/', '', $invoice['last_main_doc']);

return $this->get(self::RESOURCE_DOCUMENTS.'/download', [
'modulepart' => 'facture',
'original_file' => $originalFilename
]);
}

return null;
}

public function createInvoice(int $idUser) public function createInvoice(int $idUser)
{ {
return $this->post(self::RESOURCE_INVOICES, [ return $this->post(self::RESOURCE_INVOICES, [

+ 3
- 1
common/config/main.php View File

], ],
DeliveryNote::class => [ DeliveryNote::class => [
// Order : assignation du bon de livraison aux commandes // Order : assignation du bon de livraison aux commandes
common\logic\Order\Order\Event\DeliveryNoteObserver::class
common\logic\Order\Order\Event\DeliveryNoteObserver::class,
// DeliveryNote : validation automatique des bons de livraison
common\logic\Document\DeliveryNote\Event\DeliveryNoteObserver::class
], ],
Ticket::class => [ Ticket::class => [
// User : envoi email nouveau ticket à l'administrateur // User : envoi email nouveau ticket à l'administrateur

+ 1
- 1
common/config/params.php View File

*/ */


return [ return [
'version' => '23.11.C',
'version' => '23.12.A',
'maintenanceMode' => false, 'maintenanceMode' => false,
'siteName' => 'Opendistrib', 'siteName' => 'Opendistrib',
'adminEmail' => 'contact@opendistrib.net', 'adminEmail' => 'contact@opendistrib.net',

+ 6
- 0
common/controllers/CommonController.php View File



use common\components\BusinessLogic; use common\components\BusinessLogic;
use common\components\BusinessLogicTrait; use common\components\BusinessLogicTrait;
use common\components\ParameterBag;
use common\logic\User\User\Model\User; use common\logic\User\User\Model\User;
use yii; use yii;
use yii\web\Response; use yii\web\Response;
{ {
return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl); return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl);
} }

public function getParameterBag(): ParameterBag
{
return Yii::$app->parameterBag;
}
} }


?> ?>

+ 5
- 1
common/logic/Distribution/Distribution/Export/DistributionReportPdfGenerator.php View File

table tr td { table tr td {
font-size: 13px ; font-size: 13px ;
} }
.payment-detail-remaining-surplus {
font-size: 10px;
}
', ',
'methods' => [ 'methods' => [
'SetHeader' => ['Commandes du ' . date('d/m/Y', strtotime($distribution->date))], 'SetHeader' => ['Commandes du ' . date('d/m/Y', strtotime($distribution->date))],


public function columnOrderAmount(Order $order): string public function columnOrderAmount(Order $order): string
{ {
$html = '<td><strong>'.number_format($order->amount_with_tax, 2) . ' €</strong>';
$html = '<td class="td-order-amount"><strong>'.number_format($order->amount_with_tax, 2) . ' €</strong>';


$paymentLabelPaid = $this->orderRepository->getPaymentLabelPaid($order); $paymentLabelPaid = $this->orderRepository->getPaymentLabelPaid($order);
if($paymentLabelPaid && strlen($paymentLabelPaid)) { if($paymentLabelPaid && strlen($paymentLabelPaid)) {

+ 1
- 1
common/logic/Distribution/Distribution/Export/DistributionReportTotalProductCsvGenerator.php View File

public function generate(Distribution $distribution, bool $save = false) public function generate(Distribution $distribution, bool $save = false)
{ {
$datas = []; $datas = [];
$productsArray = $this->productRepository->findProductsByDistribution($distribution);
$productsArray = $this->productRepository->findProductsByDistribution($distribution, true,'product.order ASC');
$ordersArray = $this->orderRepository->findOrdersByDistribution($distribution); $ordersArray = $this->orderRepository->findOrdersByDistribution($distribution);


foreach($productsArray as $product) { foreach($productsArray as $product) {

+ 13
- 10
common/logic/Distribution/Distribution/Export/DistributionShoppingCartLabelsPdfGenerator.php View File

return $order->pointSale && $order->pointSale->exclude_export_shopping_cart_labels; return $order->pointSale && $order->pointSale->exclude_export_shopping_cart_labels;
} }


public function getCss(bool $isSpecificFormat = false, float $specificFormatWith = 0, float $specificFormatHeight = 0): string
public function getCss(bool $isSpecificFormat = false, float $specificFormatWidth = 0, float $specificFormatHeight = 0): string
{ {
$css = ' $css = '
@page { @page {
.shopping-cart-label .username { .shopping-cart-label .username {
font-weight: bold; font-weight: bold;
font-size: 13px;
font-size: 16px;
} }
.shopping-cart-label .point-sale { .shopping-cart-label .point-sale {
}'; }';


if($isSpecificFormat) { if($isSpecificFormat) {
$paddingShoppingCartLabel = 3;
$specificFormatWith = $specificFormatWith - 2 * $paddingShoppingCartLabel;
$specificFormatHeight = $specificFormatHeight - 2 * $paddingShoppingCartLabel;
$paddingWidthShoppingCartLabel = 8;
$paddingHeightShoppingCartLabel = 5;
$specificFormatWidth = $specificFormatWidth - 2 * $paddingWidthShoppingCartLabel;
$specificFormatHeight = $specificFormatHeight - 2 * $paddingHeightShoppingCartLabel + 1;


$css .= ' $css .= '
.shopping-cart-label { .shopping-cart-label {
box-sizing: border-box; box-sizing: border-box;
padding: '.$paddingShoppingCartLabel.'mm;
width: '.$specificFormatWith.'mm;
padding-top: '.$paddingHeightShoppingCartLabel.'mm;
padding-bottom: '.$paddingHeightShoppingCartLabel.'mm;
padding-left: '.$paddingWidthShoppingCartLabel.'mm;
padding-right: '.$paddingWidthShoppingCartLabel.'mm;
width: '.$specificFormatWidth.'mm;
height: '.$specificFormatHeight.'mm; height: '.$specificFormatHeight.'mm;
display: block; display: block;
float: left; float: left;
return $css; return $css;
} }


public function getShoppingCartLabelAsHtml(Order $order): string
public function getShoppingCartLabelAsHtml(Order $order, int $index): string
{ {
return '<div class="shopping-cart-label">
return '<div class="shopping-cart-label shopping-cart-label-'.$index.'">
<div class="inner"> <div class="inner">
<div class="username"> <div class="username">
'.$this->orderSolver->getOrderUsername($order).' '.$this->orderSolver->getOrderUsername($order).'

+ 30
- 0
common/logic/Document/DeliveryNote/Event/DeliveryNoteObserver.php View File

<?php

namespace common\logic\Document\DeliveryNote\Event;

use common\logic\Document\DeliveryNote\Event\DeliveryNoteCreateEvent;
use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Document\Document\Module\DocumentModule;
use common\logic\Order\Order\Module\OrderModule;
use common\logic\Producer\Producer\Module\ProducerModule;
use justcoded\yii2\eventlistener\observers\Observer;

class DeliveryNoteObserver extends Observer
{
public function events()
{
return [
DeliveryNote::EVENT_CREATE => 'onDeliveryNoteCreate'
];
}

public function onDeliveryNoteCreate(DeliveryNoteCreateEvent $event)
{
$producerModule = ProducerModule::getInstance();
$documentModule = DocumentModule::getInstance();

if($producerModule->getSolver()->getConfig('delivery_note_automatic_validation')) {
$documentModule->getManager()->validateDocument($event->deliveryNote);
}
}
}

+ 2
- 0
common/logic/Document/DeliveryNote/Service/DeliveryNoteBuilder.php View File

use common\logic\Document\DeliveryNote\Event\DeliveryNoteCreateEvent; use common\logic\Document\DeliveryNote\Event\DeliveryNoteCreateEvent;
use common\logic\Document\DeliveryNote\Model\DeliveryNote; use common\logic\Document\DeliveryNote\Model\DeliveryNote;
use common\logic\Document\DeliveryNote\Repository\DeliveryNoteRepository; use common\logic\Document\DeliveryNote\Repository\DeliveryNoteRepository;
use common\logic\Document\Document\Model\Document;
use common\logic\Document\Document\Service\DocumentBuilder; use common\logic\Document\Document\Service\DocumentBuilder;
use common\logic\Order\Order\Model\Order; use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Service\OrderSolver; use common\logic\Order\Order\Service\OrderSolver;
{ {
$deliveryNote = new DeliveryNote(); $deliveryNote = new DeliveryNote();


$deliveryNote->status = Document::STATUS_DRAFT;
$this->initDocumentProducer($deliveryNote); $this->initDocumentProducer($deliveryNote);
$this->initTaxCalculationMethod($deliveryNote); $this->initTaxCalculationMethod($deliveryNote);



+ 1
- 0
common/logic/Document/Document/Service/DocumentManager.php View File



if ($status == Document::STATUS_VALID) { if ($status == Document::STATUS_VALID) {
$this->documentReferenceGenerator->generateReference($document); $this->documentReferenceGenerator->generateReference($document);
$this->generatePdf($document, Pdf::DEST_FILE);
} }


$this->documentBuilder->update($document); $this->documentBuilder->update($document);

+ 9
- 8
common/logic/Order/Order/Repository/OrderRepository.php View File



use common\helpers\GlobalParam; use common\helpers\GlobalParam;
use common\helpers\MeanPayment; use common\helpers\MeanPayment;
use common\helpers\Price;
use common\logic\AbstractRepository; use common\logic\AbstractRepository;
use common\logic\Distribution\Distribution\Model\Distribution; use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Distribution\Distribution\Repository\DistributionRepository; use common\logic\Distribution\Distribution\Repository\DistributionRepository;
$titleLabel = 'Paiement partiel '.$amountPaid; $titleLabel = 'Paiement partiel '.$amountPaid;
} }


return '<span class="label label-'.$classLabel.'" title="'.$titleLabel.'">'.$label.'</span>';
$labelHtml = '<span class="label label-'.$classLabel.'" title="'.$titleLabel.'">'.$label.'</span>';

if($amountPaid) {
$labelHtml .= $this->orderSolver->getPaymentLabelAmountRemainingSurplus($order);
}

return $labelHtml;
} }


public function getPaymentLabelPaid(Order $order): string public function getPaymentLabelPaid(Order $order): string
} }
} }


$orderPaymentStatus = $this->orderSolver->getPaymentStatus($order);
if($orderPaymentStatus == Order::PAYMENT_SURPLUS) {
$label .= ' (surplus)';
}
elseif($orderPaymentStatus == Order::PAYMENT_UNPAID) {
$label .= ' (partiel)';
}
$label .= $this->orderSolver->getPaymentLabelAmountRemainingSurplus($order);
} }
} }



+ 24
- 0
common/logic/Order/Order/Service/OrderSolver.php View File

return $html; return $html;
} }


public function getPaymentLabelAmountRemainingSurplus(Order $order): string
{
$amountPaid = $this->getOrderAmountPaid($order);

if($amountPaid) {
$amountRemaining = $this->getOrderAmountWithTax($order, Order::AMOUNT_REMAINING);
if($amountRemaining > 0) {
return $this->getHtmlPaymentLabelAmountRemainingSurplus('Reste <strong>'.Price::format($amountRemaining).'</strong> à payer');
}

$amountSurplus = $this->getOrderAmountWithTax($order, Order::AMOUNT_SURPLUS);
if($amountSurplus > 0) {
return $this->getHtmlPaymentLabelAmountRemainingSurplus('Surplus : <strong>'.Price::format($amountSurplus).'</strong> à rembourser');
}
}

return '';
}

private function getHtmlPaymentLabelAmountRemainingSurplus(string $text): string
{
return '<br><span class="payment-detail-remaining-surplus">'.$text.'</span>';
}

/** /**
* Retourne l'origine de la commande (client, automatique ou admin) sous forme texte ou HTML. * Retourne l'origine de la commande (client, automatique ou admin) sous forme texte ou HTML.
*/ */

+ 8
- 0
common/logic/PointSale/PointSale/Repository/PointSaleRepository.php View File

->find(); ->find();
} }


public function findPointSalesByUserAccess(User $user)
{
return $this->createDefaultQuery()
->filterIsOnline()
->filterByUserAccess($user)
->find();
}

public function queryPointSalesPublic(Producer $producer) public function queryPointSalesPublic(Producer $producer)
{ {
return $this->createDefaultQuery() return $this->createDefaultQuery()

+ 9
- 0
common/logic/PointSale/PointSale/Repository/PointSaleRepositoryQuery.php View File

use common\logic\PointSale\PointSale\Model\PointSale; use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\PointSale\PointSale\Service\PointSaleDefinition; use common\logic\PointSale\PointSale\Service\PointSaleDefinition;
use common\logic\StatusInterface; use common\logic\StatusInterface;
use common\logic\User\User\Model\User;
use yii\db\ActiveQuery; use yii\db\ActiveQuery;


class PointSaleRepositoryQuery extends AbstractRepositoryQuery class PointSaleRepositoryQuery extends AbstractRepositoryQuery


return $this; return $this;
} }

public function filterByUserAccess(User $user): self
{
$this->andWhere('status = 1 AND (restricted_access = 0 OR (restricted_access = 1 AND (SELECT COUNT(*) FROM user_point_sale WHERE point_sale.id = user_point_sale.id_point_sale AND user_point_sale.id_user = :id_user) > 0))');
$this->addParams([':id_user' => $user->id]);

return $this;
}
} }

+ 3
- 1
common/logic/Producer/Producer/Model/Producer.php View File

'option_export_display_column_delivery_note', 'option_export_display_column_delivery_note',
'option_invoice_only_based_on_delivery_notes', 'option_invoice_only_based_on_delivery_notes',
'option_document_display_price_unit_reference', 'option_document_display_price_unit_reference',
'option_check_by_default_prevent_user_credit'
'option_check_by_default_prevent_user_credit',
'delivery_note_automatic_validation'
], ],
'boolean' 'boolean'
], ],
'option_document_display_price_unit_reference' => "Afficher les prix au kilogramme", 'option_document_display_price_unit_reference' => "Afficher les prix au kilogramme",
'id_user_group_default' => "Groupe utilisateur par défaut attribué à l'inscription", 'id_user_group_default' => "Groupe utilisateur par défaut attribué à l'inscription",
'option_check_by_default_prevent_user_credit' => "Par défaut, prévenir l'utilisateur quand on crédite son compte", 'option_check_by_default_prevent_user_credit' => "Par défaut, prévenir l'utilisateur quand on crédite son compte",
'delivery_note_automatic_validation' => 'Validation automatique des bons de livraison'
]; ];
} }



+ 10
- 0
common/logic/Producer/Producer/Service/DolibarrProducerUtils.php View File

$this->producerRepository = $this->loadService(ProducerRepository::class); $this->producerRepository = $this->loadService(ProducerRepository::class);
} }


public function getDolibarrProducerInvoices(Producer $producer): array
{
$invoicesArray = [];
if($producer->dolibarr_socid) {
$invoicesArray = $this->dolibarrApi->getInvoicesByThirParty($producer->dolibarr_socid);
}

return $invoicesArray;
}

public function generateDolibarrProducerInvoice(Producer $producer) public function generateDolibarrProducerInvoice(Producer $producer)
{ {
$idProduct = $this->getDolibarrProductId($producer); $idProduct = $this->getDolibarrProductId($producer);

+ 8
- 4
common/logic/Product/Product/Repository/ProductRepository.php View File

return $this->createDefaultQuery()->count(); return $this->createDefaultQuery()->count();
} }


public function queryProductsByDistribution(Distribution $distribution, bool $filterStatus = true)
public function queryProductsByDistribution(Distribution $distribution, bool $filterStatus = true, string $orderBy = null)
{ {
if(!$orderBy) {
$orderBy = 'product_distribution.active DESC, product.order ASC';
}

return $this->createDefaultQuery($filterStatus) return $this->createDefaultQuery($filterStatus)
->joinWith([ ->joinWith([
'productDistribution' => function ($query) use ($distribution) { 'productDistribution' => function ($query) use ($distribution) {
); );
} }
]) ])
->orderBy('product_distribution.active DESC, product.order ASC');
->orderBy($orderBy);
} }


/** /**
* Retourne les produits d'une production donnée. * Retourne les produits d'une production donnée.
*/ */
public function findProductsByDistribution(Distribution $distribution, bool $filterStatus = true)
public function findProductsByDistribution(Distribution $distribution, bool $filterStatus = true, string $orderBy = null)
{ {
$productArray = $this->queryProductsByDistribution($distribution, $filterStatus)->find();
$productArray = $this->queryProductsByDistribution($distribution, $filterStatus, $orderBy)->find();
return $this->buildProductsArrayById($productArray); return $this->buildProductsArrayById($productArray);
} }



+ 3
- 3
common/versions/23.11.C.php View File

[ [
], ],
[ [
"[Admin] Distribution > exports : ouverture dans un nouvel onglet",
"[Administration] Distribution > exports : ouverture dans un nouvel onglet",
] ]
], ],
[ [
[ [
], ],
[ [
"[Admin] Tarifs : erreur vue modules payants",
"[Admin] Produits : import prix cassé"
"[Administration] Tarifs : erreur vue modules payants",
"[Administration] Produits : import prix cassé"
] ]
], ],
$userCurrent $userCurrent

+ 28
- 0
common/versions/23.12.A.php View File

<?php

require_once dirname(__FILE__).'/_macros.php';

version(
'04/12/2023',
[
[
"[Administration] Nouvel onglet 'Mes factures' : possibilité de retrouver ses factures Opendistrib",
"[Administration] Distributions > Génération des bons de livraison : validation automatique (Paramètres > Facturation > Validation automatique des bons de livraison)",
"[Administration] Export étiquettes PDF avec format spécifique (70x42mm)",
],
[
"[Administration] Export commandes PDF : affichage du montant restant/surplus à régler",
"[Administration] Abonnements : correctif regénération commandes distributions à venir",
"[Boutique] Abonnements : correctif problème points de vente à accès restreint affichés"
]
],
[
[
],
[
]
],
$userCurrent
);

?>

+ 11
- 0
common/web/css/screen.css View File

#main #content .site-error .alert .btn { #main #content .site-error .alert .btn {
text-decoration: none; text-decoration: none;
} }

/* Paiement */
/* line 144, ../sass/_common.scss */
.payment-detail-remaining-surplus {
font-size: 13px;
color: gray;
}
/* line 148, ../sass/_common.scss */
.payment-detail-remaining-surplus strong {
font-weight: bold;
}

+ 10
- 0
common/web/sass/_common.scss View File

.actions { .actions {
//text-align: center; //text-align: center;
} }
}

/* Paiement */
.payment-detail-remaining-surplus {
font-size: 13px;
color: gray;

strong {
font-weight: bold;
}
} }

+ 26
- 0
console/migrations/m231130_082147_add_column_producer_delivery_note_automatic_validation.php View File

<?php

use yii\db\Migration;
use yii\db\Schema;

/**
* Class m231130_082147_add_column_producer_delivery_note_automatic_validation
*/
class m231130_082147_add_column_producer_delivery_note_automatic_validation extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('producer', 'delivery_note_automatic_validation', Schema::TYPE_BOOLEAN);
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropColumn('producer', 'delivery_note_automatic_validation');
}
}

+ 2
- 6
producer/controllers/CreditController.php View File

// Handle the event // Handle the event
switch ($event->type) { switch ($event->type) {
case 'charge.succeeded': case 'charge.succeeded':

$paymentExist = Payment::searchOne([ $paymentExist = Payment::searchOne([
'id_user' => $idUser, 'id_user' => $idUser,
'amount' => $amount, 'amount' => $amount,


if (!$paymentExist) { if (!$paymentExist) {


$paymentManager->creditUser($user, $amount, MeanPayment::CREDIT_CARD, $user);

if (isset($order) && $order) { if (isset($order) && $order) {

$paymentManager->payOrder($order, MeanPayment::CREDIT_CARD, $user, true); $paymentManager->payOrder($order, MeanPayment::CREDIT_CARD, $user, true);



// client : envoi d'un email de confirmation de paiement // client : envoi d'un email de confirmation de paiement
/*\Yii::$app->mailerService->sendFromProducer( /*\Yii::$app->mailerService->sendFromProducer(
'Confirmation de commande', 'Confirmation de commande',
$contactProducer->email $contactProducer->email
); );
} else { } else {
$userProducer = $this->getUserProducerModule()->findOneUserProducer($user);
$paymentManager->creditUser($user, $amount, MeanPayment::CREDIT_CARD, $user);


$userProducer = $this->getUserProducerModule()->findOneUserProducer($user);
\Yii::$app->mailerService->sendFromProducer( \Yii::$app->mailerService->sendFromProducer(
'Alimentation de votre crédit', 'Alimentation de votre crédit',
'creditConfirm', 'creditConfirm',

+ 2
- 2
producer/controllers/SubscriptionController.php View File

$params = []; $params = [];
$productModule = $this->getProductModule(); $productModule = $this->getProductModule();
$subscriptionModule = $this->getSubscriptionModule(); $subscriptionModule = $this->getSubscriptionModule();
$user = GlobalParam::getCurrentUser();
$user = $this->getUserCurrent();
$userProducer = $this->getUserProducerModule()->findOneUserProducer($this->getUserCurrent()); $userProducer = $this->getUserProducerModule()->findOneUserProducer($this->getUserCurrent());
$pointSale = null; $pointSale = null;




$params['products'] = $productsArray; $params['products'] = $productsArray;
$pointsSaleArray = $this->getPointSaleModule()->findPointSales();
$pointsSaleArray = $this->getPointSaleModule()->findPointSalesByUserAccess($user);
foreach ($pointsSaleArray as &$pointSale) { foreach ($pointsSaleArray as &$pointSale) {
$pointSale = array_merge($pointSale->getAttributes(), [ $pointSale = array_merge($pointSale->getAttributes(), [
'userPointSale' => ($pointSale->userPointSale ? $pointSale->userPointSale[0] : '') 'userPointSale' => ($pointSale->userPointSale ? $pointSale->userPointSale[0] : '')

+ 2
- 3
producer/views/order/order.php View File

v-if="countSelectedProductsByCategory(category) > 1">s</template></span> v-if="countSelectedProductsByCategory(category) > 1">s</template></span>
</td> </td>
</tr> </tr>
<template
v-if="(categoryCurrent && categoryCurrent.id == category.id) || category.id == null">
<template v-if="(categoryCurrent && categoryCurrent.id == category.id) || category.id == null">
<tr v-for="product in products" <tr v-for="product in products"
v-if="product.id_product_category == category.id && product.productDistribution && product.productDistribution[0] && product.productDistribution[0].active == 1">
v-if="product.id_product_category == category.id && isProductAvailable(product)">
<td class="photo"> <td class="photo">
<a class="product-photo" :href="product.photo_big" :title="product.name"> <a class="product-photo" :href="product.photo_big" :title="product.name">
<img v-if="product.photo.length" class="photo-product" :src="product.photo"/> <img v-if="product.photo.length" class="photo-product" :src="product.photo"/>

+ 10
- 6
producer/web/js/vuejs/order-order.js View File



if(response.data.categories) { if(response.data.categories) {
app.categories = response.data.categories ; app.categories = response.data.categories ;
if(app.countProductsByCategory(response.data.categories[0])) {
app.setCategoryCurrent(response.data.categories[0], true) ;
}
else {
app.setCategoryCurrent(response.data.categories[1], true) ;
for(keyCategory in response.data.categories) {
var category = response.data.categories[keyCategory];
if(category.id && app.countProductsByCategory(category)) {
app.setCategoryCurrent(category, true) ;
break;
}
} }
} }


} }
return this.producer.credit_limit == null || (this.producer.credit_limit != null && (this.user.credit - total >= this.producer.credit_limit)) ; return this.producer.credit_limit == null || (this.producer.credit_limit != null && (this.user.credit - total >= this.producer.credit_limit)) ;
}, },
isProductAvailable: function(product) {
return product.productDistribution && product.productDistribution[0] && product.productDistribution[0].active == 1;
},
countProductsByCategory: function(category) { countProductsByCategory: function(category) {
var count = 0 ; var count = 0 ;
for(var i = 0 ; i < this.products.length ; i++) { for(var i = 0 ; i < this.products.length ; i++) {
if(this.products[i].id_product_category == category.id) {
if(this.products[i].id_product_category == category.id && this.isProductAvailable(this.products[i])) {
count ++ ; count ++ ;
} }
} }

Loading…
Cancel
Save