@@ -1475,6 +1475,7 @@ class DistributionController extends BackendController | |||
if (!$deliveryNote) { | |||
$deliveryNote = new DeliveryNote(); | |||
$deliveryNote->initTaxCalculationMethod(); | |||
$deliveryNote->id_producer = GlobalParam::getCurrentProducerId(); | |||
$deliveryNote->id_user = $order->id_user; | |||
$deliveryNote->name = 'Bon de livraison ' . $order->getUsername() . ' (' . date( | |||
@@ -1560,6 +1561,7 @@ class DistributionController extends BackendController | |||
// génération du BL | |||
if (!$deliveryNote) { | |||
$deliveryNote = new DeliveryNote; | |||
$deliveryNote->initTaxCalculationMethod(); | |||
$deliveryNote->name = 'Bon de livraison ' . $firstOrder->pointSale->name . ' (' . date( | |||
'd/m/Y', | |||
strtotime( | |||
@@ -1573,6 +1575,11 @@ class DistributionController extends BackendController | |||
$user = User::searchOne([ | |||
'id' => $deliveryNote->id_user | |||
]); | |||
$userProducer = UserProducer::searchOne([ | |||
'id_user' => $deliveryNote->id_user, | |||
'id_producer' => GlobalParam::getCurrentProducerId( | |||
) | |||
]); | |||
} else { | |||
$user = new User; | |||
$user->type = User::TYPE_LEGAL_PERSON; | |||
@@ -1603,7 +1610,7 @@ class DistributionController extends BackendController | |||
$deliveryNote->address = $user->getFullAddress(); | |||
$deliveryNote->save(); | |||
} else { | |||
// réinitialisation des order.id_delivery_order | |||
// réinitialisation des order.id_delivery_note | |||
Order::updateAll([ | |||
'id_delivery_note' => null | |||
], [ |
@@ -39,13 +39,16 @@ | |||
namespace backend\controllers; | |||
use common\models\DeliveryNote; | |||
use common\models\Invoice; | |||
use common\models\PointSale; | |||
use common\models\Product; | |||
use common\models\Quotation; | |||
use common\models\User; | |||
use common\models\Document; | |||
use common\helpers\GlobalParam; | |||
use common\models\Order; | |||
use common\models\UserProducer; | |||
use kartik\mpdf\Pdf; | |||
use yii\base\UserException; | |||
use yii; | |||
@@ -74,10 +77,26 @@ class DocumentController extends BackendController | |||
]; | |||
} | |||
public function actionGeneratePdfValidatedDocuments() | |||
{ | |||
set_time_limit(0); | |||
$validatedDocumentsArray = array_merge( | |||
Quotation::find()->where(['status' => Document::STATUS_VALID])->all(), | |||
DeliveryNote::find()->where(['status' => Document::STATUS_VALID])->all(), | |||
Invoice::find()->where(['status' => Document::STATUS_VALID])->all() | |||
); | |||
foreach($validatedDocumentsArray as $document) { | |||
$document->generatePdf(Pdf::DEST_FILE); | |||
} | |||
} | |||
public function actionCreate() | |||
{ | |||
$class = $this->getClass(); | |||
$model = new $class(); | |||
$model->initTaxCalculationMethod(); | |||
if ($model->load(Yii::$app->request->post())) { | |||
$model->id_producer = GlobalParam::getCurrentProducerId(); | |||
@@ -178,10 +197,121 @@ class DocumentController extends BackendController | |||
$this->redirect([$this->getControllerUrl() . '/index']); | |||
} | |||
public function actionExportCsvEvoliz($id) | |||
{ | |||
$datas = []; | |||
$document = $this->findModel($id); | |||
// données | |||
$datas[] = [ | |||
'N° facture externe *', | |||
'Date facture *', | |||
'Client', | |||
'Code client *', | |||
'Total TVA', | |||
'Total HT', | |||
'Total TTC', | |||
'Total réglé', | |||
'Etat', | |||
'Date Etat', | |||
'Date de création', | |||
'Objet', | |||
'Date d\'échéance', | |||
'Date d\'exécution', | |||
'Taux de pénalité', | |||
'Frais de recouvrement', | |||
'Taux d\'escompte', | |||
'Conditions de règlement *', | |||
'Mode de paiement', | |||
'Remise globale', | |||
'Acompte', | |||
'Nombre de relance', | |||
'Commentaires', | |||
'N° facture', | |||
'Annulé', | |||
'Catalogue', | |||
'Réf.', | |||
'Désignation *', | |||
'Qté *', | |||
'Unité', | |||
'PU HT *', | |||
'Remise', | |||
'TVA', | |||
'Total TVA', | |||
'Total HT', | |||
'Créateur', | |||
]; | |||
foreach($document->getProductsOrders() as $productOrderArray) { | |||
foreach($productOrderArray as $productOrder) { | |||
$price = $productOrder->getPrice() ; | |||
if($document->isInvoicePrice() && $productOrder->getInvoicePrice()) { | |||
$price = $productOrder->getInvoicePrice() ; | |||
} | |||
$datas[] = [ | |||
$document->reference, // N° facture externe * | |||
date('d/m/Y', strtotime($document->date)), // Date facture * | |||
'', // Client | |||
$document->user->evoliz_code, // Code client * | |||
'', // Total TVA | |||
'', // Total HT | |||
'', // Total TTC | |||
'', // Total réglé | |||
'', // Etat | |||
'', // Date Etat | |||
'', // Date de création | |||
$document->name, // Objet | |||
'', // Date d'échéance | |||
'', // Date d'exécution | |||
'', // Taux de pénalité | |||
'', // Frais de recouvrement | |||
'', // Taux d\'escompte | |||
'A réception', // Conditions de règlement * | |||
'', // Mode de paiement | |||
'', // Remise globale | |||
'', // Acompte | |||
'', // Nombre de relance | |||
'', // Commentaires | |||
'', // N° facture | |||
'', // Annulé | |||
'Non', // Catalogue | |||
'', // Réf. | |||
$productOrder->product->name, // Désignation * | |||
$productOrder->quantity, // Qté * | |||
'', // Product::strUnit($productOrder->unit, 'wording'), // Unité | |||
$price, // PU HT * | |||
'', // Remise | |||
$productOrder->taxRate->value * 100, // TVA | |||
'', // Total TVA | |||
'', // Total HT | |||
'', // Créateur | |||
]; | |||
} | |||
} | |||
// nom fichier | |||
$reference = $document->id; | |||
if($document->reference && strlen($document->reference)) { | |||
$reference = $document->reference; | |||
} | |||
// status | |||
$status = ''; | |||
if($document->isStatusDraft()) { | |||
$status = 'brouillon_'; | |||
} | |||
CSV::downloadSendHeaders(strtolower($this->getDocumentType()).'_' . $status . $reference . '.csv'); | |||
echo CSV::array2csv($datas); | |||
die(); | |||
} | |||
public function actionDownload($id) | |||
{ | |||
$document = $this->findModel($id); | |||
return $document->generatePdf(Pdf::DEST_BROWSER); | |||
return $document->downloadPdf(); | |||
} | |||
public function actionSend($id) | |||
@@ -273,6 +403,10 @@ class DocumentController extends BackendController | |||
if ($document) { | |||
$document->changeStatus(Document::STATUS_VALID); | |||
$document->save(); | |||
// génération PDF | |||
$document->generatePdf(Pdf::DEST_FILE); | |||
Yii::$app->getSession()->setFlash('success', $this->getFlashMessage('validate', $document)); | |||
return $this->redirect([$this->getControllerUrl() . '/index']); | |||
} |
@@ -99,14 +99,14 @@ class ProducerAdminController extends BackendController | |||
$producersArray = Producer::find()->where('active = 1')->all(); | |||
$sumFreePrice = 0 ; | |||
$sumPrices = 0; | |||
foreach($producersArray as $producer) { | |||
$sumFreePrice += $producer->free_price ; | |||
$sumPrices += $producer->getAmountBilledLastMonth(); | |||
} | |||
return $this->render('index', [ | |||
'dataProviderProducer' => $dataProviderProducer, | |||
'sumFreePrice' => $sumFreePrice | |||
'sumPrices' => $sumPrices | |||
]); | |||
} | |||
@@ -0,0 +1,163 @@ | |||
<?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. | |||
*/ | |||
namespace backend\controllers; | |||
use common\models\ProducerPriceRange; | |||
use Yii; | |||
use common\models\User; | |||
use yii\web\NotFoundHttpException; | |||
use yii\filters\VerbFilter; | |||
use yii\filters\AccessControl; | |||
use yii\data\ActiveDataProvider; | |||
/** | |||
* TaxRateAdminController implements the CRUD actions for TaxRate model. | |||
*/ | |||
class ProducerPriceRangeAdminController extends BackendController | |||
{ | |||
public function behaviors() | |||
{ | |||
return [ | |||
'verbs' => [ | |||
'class' => VerbFilter::className(), | |||
'actions' => [ | |||
], | |||
], | |||
'access' => [ | |||
'class' => AccessControl::className(), | |||
'rules' => [ | |||
[ | |||
'allow' => true, | |||
'roles' => ['@'], | |||
'matchCallback' => function ($rule, $action) { | |||
return User::getCurrentStatus() == USER::STATUS_ADMIN; | |||
} | |||
] | |||
], | |||
], | |||
]; | |||
} | |||
/** | |||
* Liste les tranches de prix. | |||
* | |||
* @return mixed | |||
*/ | |||
public function actionIndex() | |||
{ | |||
$dataProvider = new ActiveDataProvider([ | |||
'query' => ProducerPriceRange::find()->orderBy('range_begin ASC') | |||
]); | |||
return $this->render('index', [ | |||
'dataProviderProducerPriceRange' => $dataProvider, | |||
]); | |||
} | |||
/** | |||
* Crée une tranche de prix. | |||
* | |||
* @return mixed | |||
*/ | |||
public function actionCreate() | |||
{ | |||
$model = new ProducerPriceRange(); | |||
if ($model->load(Yii::$app->request->post()) && $model->save()) { | |||
Yii::$app->getSession()->setFlash('success', 'Tranche de prix créée.'); | |||
return $this->redirect(['index']); | |||
} else { | |||
return $this->render('create', [ | |||
'model' => $model, | |||
]); | |||
} | |||
} | |||
/** | |||
* Édition d'une tranche de prix. | |||
* | |||
* @return mixed | |||
*/ | |||
public function actionUpdate($id) | |||
{ | |||
$model = $this->findModel($id); | |||
if ($model->load(Yii::$app->request->post()) && $model->save()) { | |||
Yii::$app->getSession()->setFlash('success', 'Tranche de prix éditée.'); | |||
return $this->redirect(['index']); | |||
} else { | |||
return $this->render('update', [ | |||
'model' => $model, | |||
]); | |||
} | |||
} | |||
/** | |||
* Supprime une tranche de prix. | |||
* | |||
* @param integer $id | |||
*/ | |||
public function actionDelete($id) | |||
{ | |||
$producerPriceRange = ProducerPriceRange::searchOne([ | |||
'id' => $id | |||
]) ; | |||
$producerPriceRange->delete(); | |||
Yii::$app->getSession()->setFlash('success', 'Tranche de prix supprimée.'); | |||
return $this->redirect(['producer-price-range-admin/index']); | |||
} | |||
/** | |||
* Finds the Developpement model based on its primary key value. | |||
* If the model is not found, a 404 HTTP exception will be thrown. | |||
* @param integer $id | |||
* @return ProducerPriceRange the loaded model | |||
* @throws NotFoundHttpException if the model cannot be found | |||
*/ | |||
protected function findModel($id) | |||
{ | |||
if (($model = ProducerPriceRange::findOne($id)) !== null) { | |||
return $model; | |||
} else { | |||
throw new NotFoundHttpException('The requested page does not exist.'); | |||
} | |||
} | |||
} |
@@ -90,6 +90,7 @@ class QuotationController extends DocumentController | |||
if($quotation->isStatusValid()) { | |||
$invoice = new Invoice ; | |||
$invoice->initTaxCalculationMethod(); | |||
$invoice->id_producer = GlobalParam::getCurrentProducerId(); | |||
$invoice->id_user = $quotation->id_user ; | |||
$invoice->address = $quotation->address ; |
@@ -1,10 +1,12 @@ | |||
<tr class="<?php if(isset($displayOrders) && $displayOrders): ?>order<?php endif; ?>"> | |||
<td class="align-left"> | |||
<?= Html::encode($productOrder->product->name) ?> | |||
<?php if($productOrder->product): ?> | |||
<?= Html::encode($productOrder->product->name) ?> | |||
<?php endif; ?> | |||
<?php if($productOrder->unit == 'piece' && isset($productOrder->product->weight) && $productOrder->product->weight): ?> | |||
<span class="weight"> / <?= $productOrder->product->weight ?> g</span> | |||
<?php endif; ?> | |||
<?php if(strlen($productOrder->product->description) && $displayProductDescription): ?> | |||
<?php if($productOrder->product && strlen($productOrder->product->description) && $displayProductDescription): ?> | |||
<br /><small><?= Html::encode($productOrder->product->description) ?></small> | |||
<?php endif; ?> | |||
</td> |
@@ -155,6 +155,9 @@ use common\models\Producer; | |||
<span class="info-box-icon bg-blue"><i class="fa fa-download"></i></span> | |||
<div class="info-box-content"> | |||
<a href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl().'/download', 'id' => $model->id]) ?>" class="btn btn-default"><span class="glyphicon glyphicon-download-alt"></span> Télécharger (PDF)</a> | |||
<?php if($model->getClass() == 'Invoice' && Producer::getConfig('option_export_evoliz')): ?> | |||
<a href="<?= Yii::$app->urlManager->createUrl([Yii::$app->controller->getControllerUrl().'/export-csv-evoliz', 'id' => $model->id]) ?>" class="btn btn-default"><span class="glyphicon glyphicon-save-file"></span> Export Evoliz (CSV)</a> | |||
<?php endif; ?> | |||
</div> | |||
</div> | |||
<div v-if="document.status == 'draft'" id="" class="info-box"> |
@@ -81,7 +81,9 @@ $displayProductDescription = Producer::getConfig('document_display_product_descr | |||
<tr> | |||
<td> | |||
<strong><?= Html::encode($order->getUsername()) ; ?></strong> | |||
le <?= date('d/m/Y', strtotime($order->distribution->date)) ?> | |||
<?php if($order->distribution): ?> | |||
le <?= date('d/m/Y', strtotime($order->distribution->date)) ?> | |||
<?php endif; ?> | |||
</td> | |||
<?php if($displayPrices): ?> | |||
<td class="align-center"></td> | |||
@@ -128,10 +130,24 @@ $displayProductDescription = Producer::getConfig('document_display_product_descr | |||
<?= Price::format($document->getAmount($typeAmount)); ?> | |||
</td> | |||
</tr> | |||
<tr> | |||
<?php | |||
$taxRateArray = TaxRate::getTaxRateArray(); | |||
foreach($document->getTotalVatArray($typeAmount) as $idTaxRate => $totalVat): ?> | |||
<tr> | |||
<td class="align-right" colspan="5"><strong>TVA <?= $taxRateArray[$idTaxRate]->value * 100 ?> %</strong></td> | |||
<td class="align-center"> | |||
<?= Price::format($totalVat); ?> | |||
</td> | |||
</tr> | |||
<?php endforeach; ?> | |||
<!--<tr> | |||
<td class="align-right" colspan="5"><strong>TVA</strong></td> | |||
<td class="align-center"><?= Price::format($document->getAmountWithTax($typeAmount) - $document->getAmount($typeAmount)) ?></td> | |||
</tr> | |||
<td class="align-center"> | |||
<?= Price::format($document->getAmountWithTax($typeAmount) - $document->getAmount($typeAmount)) ?> | |||
</td> | |||
</tr>--> | |||
<tr> | |||
<td class="align-right" colspan="5"><strong>Total TTC</strong></td> | |||
<td class="align-center"><?= Price::format($document->getAmountWithTax($typeAmount)) ?></td> |
@@ -101,7 +101,7 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon- | |||
], | |||
[ | |||
'class' => 'yii\grid\ActionColumn', | |||
'template' => '{validate} {update} {delete} {send} {download}', | |||
'template' => '{validate} {update} {delete} {send} {download} {export-csv-evoliz}', | |||
'headerOptions' => ['class' => 'column-actions'], | |||
'contentOptions' => ['class' => 'column-actions'], | |||
'buttons' => [ | |||
@@ -120,6 +120,15 @@ $this->addButton(['label' => 'Nouvelle facture <span class="glyphicon glyphicon- | |||
'title' => 'Télécharger', 'class' => 'btn btn-default' | |||
]); | |||
}, | |||
'export-csv-evoliz' => function($url, $model) { | |||
if(Producer::getConfig('option_export_evoliz')) { | |||
return Html::a('<span class="glyphicon glyphicon-save-file"></span> Evoliz', $url, [ | |||
'title' => 'Export CSV Evoliz', 'class' => 'btn btn-default' | |||
]); | |||
} | |||
return ''; | |||
}, | |||
'update' => function ($url, $model) { | |||
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [ | |||
'title' => 'Modifier', 'class' => 'btn btn-default' |
@@ -98,6 +98,7 @@ termes. | |||
['label' => 'Administration', 'options' => ['class' => 'header'], 'visible' => User::isCurrentAdmin()], | |||
['label' => 'Producteurs','icon' => 'th-list','url' => ['/producer-admin/index'], 'visible' => User::isCurrentAdmin()], | |||
['label' => 'Tranches de prix','icon' => 'eur','url' => ['/producer-price-range-admin/index'], 'visible' => User::isCurrentAdmin()], | |||
['label' => 'Taxes','icon' => 'eur','url' => ['/tax-rate-admin/index'], 'visible' => User::isCurrentAdmin()], | |||
['label' => 'Communiquer','icon' => 'bullhorn','url' => ['/communicate-admin/index'], 'visible' => User::isCurrentAdmin()], | |||
@@ -49,28 +49,48 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico | |||
?> | |||
<div class="alert alert-info"> | |||
Abonnements mensuels : <strong><?= $sumFreePrice ?> € HT</strong> | |||
Facturé le mois dernier : <strong><?= $sumPrices ?> €</strong><br /> | |||
</div> | |||
<?= GridView::widget([ | |||
'dataProvider' => $dataProviderProducer, | |||
'columns' => [ | |||
'name', | |||
[ | |||
'attribute' => 'active', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
$html = '' ; | |||
if($model->active) { | |||
$html .= '<span class="label label-success">En ligne</span>' ; | |||
} | |||
else { | |||
$html .= '<span class="label label-danger">Hors-ligne</span>' ; | |||
} | |||
if(strlen($model->code)) | |||
{ | |||
$html .= ' <span class="glyphicon glyphicon-lock" data-toggle="tooltip" data-placement="bottom" data-original-title="'.Html::encode($model->code).'"></span>' ; | |||
} | |||
return $html ; | |||
} | |||
], | |||
'name', | |||
/*[ | |||
'attribute' => 'date_creation', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
return date('d/m/Y', strtotime($model->date_creation)) ; | |||
} | |||
], | |||
[ | |||
],*/ | |||
/*[ | |||
'attribute' => 'Lieu', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
return Html::encode($model->city.' ('.$model->postcode.')') ; | |||
} | |||
], | |||
[ | |||
],*/ | |||
/*[ | |||
'attribute' => 'Utilisateurs', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
@@ -87,7 +107,7 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico | |||
} | |||
} | |||
], | |||
],*/ | |||
[ | |||
'attribute' => 'Contact', | |||
'format' => 'raw', | |||
@@ -111,63 +131,60 @@ $this->addButton(['label' => 'Nouveau producteur <span class="glyphicon glyphico | |||
} | |||
], | |||
[ | |||
'attribute' => 'active', | |||
'attribute' => 'Prix libre', | |||
'label' => 'Prix libre', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
$html = '' ; | |||
if($model->active) { | |||
$html .= '<span class="label label-success">En ligne</span>' ; | |||
if(is_null($model->free_price)) { | |||
return '' ; | |||
} | |||
else { | |||
$html .= '<span class="label label-danger">Hors-ligne</span>' ; | |||
} | |||
if(strlen($model->code)) | |||
{ | |||
$html .= ' <span class="glyphicon glyphicon-lock" data-toggle="tooltip" data-placement="bottom" data-original-title="'.Html::encode($model->code).'"></span>' ; | |||
$str = ''; | |||
if($model->isBillingTypeFreePrice()) { | |||
$str .= '<strong>'; | |||
} | |||
$str .= $model->getFreePrice(); | |||
if($model->isBillingTypeFreePrice()) { | |||
$str .= '</strong>'; | |||
} | |||
return $str; | |||
} | |||
return $html ; | |||
} | |||
], | |||
[ | |||
'attribute' => 'Prix libre', | |||
'label' => 'Prix libre', | |||
'attribute' => 'À facturer / chiffre d\'affaire', | |||
'label' => 'À facturer / chiffre d\'affaire', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
if(is_null($model->free_price)) { | |||
return '' ; | |||
if($model->isBillingFrequencyMonthly()) { | |||
return $model->getSummaryAmountsToBeBilled('Mois dernier', 1); | |||
} | |||
else { | |||
return $model->getFreePrice() ; | |||
elseif($model->isBillingFrequencyQuarterly()) { | |||
return $model->getSummaryAmountsToBeBilled('3 derniers mois', 3); | |||
} | |||
elseif($model->isBillingFrequencyBiannual()) { | |||
return $model->getSummaryAmountsToBeBilled('6 derniers mois', 6); | |||
} | |||
} | |||
], | |||
[ | |||
'label' => 'Dons (mois précédent)', | |||
'attribute' => 'Facturation', | |||
'label' => 'Détails facturation', | |||
'format' => 'raw', | |||
'value' => function($model) { | |||
$productGift = Product::getProductGift() ; | |||
$res = Yii::$app->db->createCommand("SELECT SUM(product_order.price * product_order.quantity) AS total | |||
FROM `order`, product_order, distribution | |||
WHERE distribution.id_producer = :id_producer | |||
AND `order`.id_distribution = distribution.id | |||
AND `order`.id = product_order.id_order | |||
AND distribution.date >= :date_start | |||
AND distribution.date <= :date_end | |||
AND product_order.id_product = :id_product_gift | |||
") | |||
->bindValue(':id_producer', $model->id) | |||
->bindValue(':date_start', date('Y-m-01', strtotime("-1 month"))) | |||
->bindValue(':date_end', date('Y-m-31', strtotime("-1 month"))) | |||
->bindValue(':id_product_gift', $productGift->id) | |||
->queryOne(); | |||
return Price::format($res['total']) ; | |||
$str = ''; | |||
$str .= '- '.Producer::$billingTypeArray[$model->option_billing_type].'<br />'; | |||
$str .= '- '.Producer::$billingFrequencyArray[$model->option_billing_frequency]; | |||
if($model->option_billing_reduction) { | |||
$str .= '<br />- <u>Avec réduction</u>'; | |||
} | |||
return $str; | |||
} | |||
], | |||
] | |||
], | |||
]); ?> |
@@ -0,0 +1,59 @@ | |||
<?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. | |||
*/ | |||
use yii\helpers\Html; | |||
use yii\widgets\ActiveForm; | |||
use yii\helpers\ArrayHelper ; | |||
use common\models\Producer ; | |||
$this->setTitle('Ajouter une tranche de prix') ; | |||
$this->addBreadcrumb(['label' => 'tranche de prix', 'url' => ['index']]) ; | |||
$this->addBreadcrumb('Ajouter') ; | |||
?> | |||
<div class="producer-price-range-create"> | |||
<?php $form = ActiveForm::begin(); ?> | |||
<?= $form->field($model, 'range_begin') ?> | |||
<?= $form->field($model, 'range_end') ?> | |||
<?= $form->field($model, 'price') ?> | |||
<div class="form-group"> | |||
<?= Html::submitButton('Ajouter', ['class' => 'btn btn-success']) ?> | |||
</div> | |||
<?php ActiveForm::end(); ?> | |||
</div> |
@@ -0,0 +1,94 @@ | |||
<?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. | |||
*/ | |||
use yii\helpers\Html; | |||
use yii\grid\GridView; | |||
use common\models\User; | |||
use common\models\Producer; | |||
use common\models\Distribution; | |||
$this->setTitle('Tranches de prix'); | |||
$this->addBreadcrumb($this->getTitle()); | |||
$this->addButton(['label' => 'Nouvelle tranche de prix <span class="glyphicon glyphicon-plus"></span>', 'url' => 'producer-price-range-admin/create', 'class' => 'btn btn-primary']); | |||
?> | |||
<?= GridView::widget([ | |||
'dataProvider' => $dataProviderProducerPriceRange, | |||
'columns' => [ | |||
[ | |||
'attribute' => 'range_begin', | |||
'value' => function ($model) { | |||
return Price::format($model->range_begin); | |||
} | |||
], | |||
[ | |||
'attribute' => 'range_end', | |||
'value' => function ($model) { | |||
if($model->range_end) { | |||
return Price::format($model->range_end); | |||
} | |||
return ''; | |||
} | |||
], | |||
[ | |||
'attribute' => 'price', | |||
'value' => function ($model) { | |||
return Price::format($model->price); | |||
} | |||
], | |||
[ | |||
'class' => 'yii\grid\ActionColumn', | |||
'template' => '{update} {delete}', | |||
'headerOptions' => ['class' => 'column-actions'], | |||
'contentOptions' => ['class' => 'column-actions'], | |||
'buttons' => [ | |||
'update' => function ($url, $model) { | |||
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [ | |||
'title' => Yii::t('app', 'Modifier'), 'class' => 'btn btn-default' | |||
]); | |||
}, | |||
'delete' => function ($url, $model) { | |||
return Html::a('<span class="glyphicon glyphicon-trash"></span>', $url, [ | |||
'title' => Yii::t('app', 'Supprimer'), 'class' => 'btn btn-default' | |||
]); | |||
} | |||
], | |||
], | |||
], | |||
]); ?> |
@@ -0,0 +1,59 @@ | |||
<?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. | |||
*/ | |||
use yii\helpers\Html; | |||
use yii\widgets\ActiveForm; | |||
use yii\helpers\ArrayHelper ; | |||
use common\models\Producer ; | |||
$this->setTitle('Éditer une taxe') ; | |||
$this->addBreadcrumb(['label' => 'taxe', 'url' => ['index']]) ; | |||
$this->addBreadcrumb('Éditer') ; | |||
?> | |||
<div class="tax-create"> | |||
<?php $form = ActiveForm::begin(); ?> | |||
<?= $form->field($model, 'range_begin') ?> | |||
<?= $form->field($model, 'range_end') ?> | |||
<?= $form->field($model, 'price') ?> | |||
<div class="form-group"> | |||
<?= Html::submitButton('Ajouter', ['class' => 'btn btn-success']) ?> | |||
</div> | |||
<?php ActiveForm::end(); ?> | |||
</div> |
@@ -48,10 +48,16 @@ $this->addBreadcrumb($this->getTitle()) ; | |||
?> | |||
<script> | |||
var appInitValues = { | |||
isAdmin: <?= (int) User::isCurrentAdmin() ?> | |||
}; | |||
</script> | |||
<div class="user-update" id="app-producer-update"> | |||
<div id="nav-params"> | |||
<button v-for="section in sectionsArray" :class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')" @click="changeSection(section)"> | |||
<button v-for="section in sectionsArray" v-if="!section.isAdminSection || (section.isAdminSection && isAdmin)" :class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')" @click="changeSection(section)"> | |||
{{ section.nameDisplay }} | |||
<span class="glyphicon glyphicon-triangle-bottom"></span> | |||
</button> | |||
@@ -426,6 +432,12 @@ $this->addBreadcrumb($this->getTitle()) ; | |||
<?= $form->field($model, 'id_tax_rate_default') | |||
->dropDownList(ArrayHelper::map(TaxRate::find()->all(), 'id', function($model) { return $model->name; })) | |||
->label('TVA à appliquer par défaut'); ?> | |||
<?= $form->field($model, 'option_tax_calculation_method') | |||
->dropDownList(Document::$taxCalculationMethodArray); ?> | |||
<?= $form->field($model, 'option_export_evoliz')->dropDownList([ | |||
0 => 'Non', | |||
1 => 'Oui' | |||
]) ; ?> | |||
<?= $form->field($model, 'document_quotation_prefix') ; ?> | |||
<?= $form->field($model, 'document_quotation_first_reference') ; ?> | |||
<?= $form->field($model, 'document_quotation_duration') ; ?> | |||
@@ -459,7 +471,25 @@ $this->addBreadcrumb($this->getTitle()) ; | |||
->textarea(['rows' => 15]) ?> | |||
</div> | |||
</div> | |||
<?php if(User::isCurrentAdmin()): ?> | |||
<div v-show="currentSection == 'administration'" class="panel panel-default"> | |||
<div class="panel-heading"> | |||
<h3 class="panel-title">Administration</h3> | |||
</div> | |||
<div class="panel-body"> | |||
<?= $form->field($model, 'option_billing_type') | |||
->dropDownList(Producer::getBillingTypePopulateDropdown()); ?> | |||
<?= $form->field($model, 'option_billing_frequency') | |||
->dropDownList(Producer::getBillingFrequencyPopulateDropdown()); ?> | |||
<?= $form->field($model, 'option_billing_reduction') | |||
->dropDownList([ | |||
0 => 'Non', | |||
1 => 'Oui' | |||
]); ?> | |||
</div> | |||
</div> | |||
<?php endif; ?> | |||
<div class="form-group"> | |||
<?= Html::submitButton('Mettre à jour', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> |
@@ -61,6 +61,11 @@ use common\models\ProductPrice ; | |||
<?= $form->field($model, 'phone')->textInput() ?> | |||
<?= $form->field($model, 'email')->textInput() ?> | |||
<?= $form->field($model, 'address')->textarea() ?> | |||
<?php if(Producer::getConfig('option_export_evoliz')): ?> | |||
<?= $form->field($model, 'evoliz_code')->textInput() ?> | |||
<?php endif; ?> | |||
<?= $form->field($model, 'points_sale')->checkboxlist( | |||
ArrayHelper::map($pointsSaleArray, 'id', function ($pointSale) use ($model) { | |||
$commentUserPointSale = isset($pointSale->userPointSale[0]) ? $pointSale->userPointSale[0]->comment : ''; |
@@ -1,2 +1,3 @@ | |||
/index.php | |||
/index-test.php | |||
/pdf/* |
@@ -37,42 +37,57 @@ termes. | |||
var app = new Vue({ | |||
el: '#app-producer-update', | |||
data: { | |||
currentSection: 'general', | |||
sectionsArray: [ | |||
{ | |||
name: 'general', | |||
nameDisplay: 'Général' | |||
}, | |||
{ | |||
name: 'tableau-bord', | |||
nameDisplay: 'Tableau de bord' | |||
}, | |||
{ | |||
name: 'prise-commande', | |||
nameDisplay: 'Prise de commande' | |||
}, | |||
{ | |||
name: 'abonnements', | |||
nameDisplay: 'Abonnements' | |||
}, | |||
{ | |||
name: 'credit-payment', | |||
nameDisplay: 'Crédit' | |||
}, | |||
{ | |||
name: 'infos', | |||
nameDisplay: 'Informations légales' | |||
}, | |||
{ | |||
name: 'logiciels-caisse', | |||
nameDisplay: 'Logiciels de caisse' | |||
}, | |||
{ | |||
name: 'facturation', | |||
nameDisplay: 'Facturation' | |||
} | |||
] | |||
data() { | |||
return Object.assign({ | |||
currentSection: 'general', | |||
sectionsArray: [ | |||
{ | |||
name: 'general', | |||
nameDisplay: 'Général', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'tableau-bord', | |||
nameDisplay: 'Tableau de bord', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'prise-commande', | |||
nameDisplay: 'Prise de commande', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'abonnements', | |||
nameDisplay: 'Abonnements', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'credit-payment', | |||
nameDisplay: 'Crédit', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'infos', | |||
nameDisplay: 'Informations légales', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'logiciels-caisse', | |||
nameDisplay: 'Logiciels de caisse', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'facturation', | |||
nameDisplay: 'Facturation', | |||
isAdminSection: 0 | |||
}, | |||
{ | |||
name: 'administration', | |||
nameDisplay: 'Administration', | |||
isAdminSection: 1 | |||
} | |||
] | |||
}, window.appInitValues); | |||
}, | |||
methods: { | |||
changeSection: function(section) { |
@@ -52,7 +52,7 @@ class CSV | |||
// clés | |||
//fputcsv($df, array_keys(reset($array))); | |||
foreach ($array as $row) { | |||
fputcsv($df, $row); | |||
fputcsv($df, $row, ";"); | |||
} | |||
fclose($df); | |||
return ob_get_clean(); |
@@ -46,14 +46,33 @@ class Price | |||
return self::numberTwoDecimals($number).' €'; | |||
} | |||
public static function round($number) | |||
{ | |||
return round($number, 2, PHP_ROUND_HALF_UP); | |||
} | |||
public static function getPrice($priceWithTax, $taxRate) | |||
{ | |||
return floatval($priceWithTax) / ($taxRate + 1); | |||
} | |||
public static function getPriceWithTax($priceWithoutTax, $taxRate) | |||
public static function getPriceWithTax($priceWithoutTax, $taxRate, $taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT) | |||
{ | |||
return self::numberTwoDecimals(floatval($priceWithoutTax) * ($taxRate + 1)) ; | |||
$priceWithoutTax = self::round($priceWithoutTax); | |||
$vat = self::getVat($priceWithoutTax, $taxRate, $taxCalculationMethod); | |||
return $priceWithoutTax + $vat; | |||
} | |||
public static function getVat($priceTotalWithoutTax, $taxRate, $taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT) | |||
{ | |||
$vat = $priceTotalWithoutTax * $taxRate; | |||
if($taxCalculationMethod == Document::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS) { | |||
$vat = self::round($vat); | |||
} | |||
return $vat; | |||
} | |||
public static function numberTwoDecimals($number) |
@@ -39,357 +39,450 @@ | |||
namespace common\models; | |||
use common\helpers\GlobalParam; | |||
use kartik\mpdf\Pdf; | |||
use Symfony\Component\Finder\Exception\DirectoryNotFoundException; | |||
use yii\base\ErrorException; | |||
class Document extends ActiveRecordCommon | |||
{ | |||
const STATUS_DRAFT = 'draft'; | |||
const STATUS_VALID = 'valid'; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['name', 'id_user'], 'required'], | |||
[['date'], 'safe'], | |||
[['comment', 'address'], 'string'], | |||
[['id_user', 'id_producer'], 'integer'], | |||
[['name', 'reference', 'status'], 'string', 'max' => 255], | |||
[['deliveryNotes'], 'safe'] | |||
]; | |||
const STATUS_DRAFT = 'draft'; | |||
const STATUS_VALID = 'valid'; | |||
const TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS = 'sum-roundings'; | |||
const TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM = 'rounding-sum'; | |||
const TAX_CALCULATION_METHOD_DEFAULT = self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM; | |||
public static $taxCalculationMethodArray = [ | |||
self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM => 'Arrondi de la somme des lignes', | |||
self::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS => 'Somme des arrondis de chaque ligne' | |||
]; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['name', 'id_user'], 'required'], | |||
[['date'], 'safe'], | |||
[['comment', 'address', 'tax_calculation_method'], 'string'], | |||
[['id_user', 'id_producer'], 'integer'], | |||
[['name', 'reference', 'status'], 'string', 'max' => 255], | |||
[['deliveryNotes'], 'safe'] | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'name' => 'Nom', | |||
'reference' => 'Référence', | |||
'date' => 'Date', | |||
'comment' => 'Commentaire', | |||
'id_user' => 'Utilisateur', | |||
'address' => 'Adresse', | |||
'id_producer' => 'Producteur', | |||
'status' => 'Statut', | |||
'tax_calculation_method' => 'Méthode de calcul de la TVA' | |||
]; | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getUser() | |||
{ | |||
return $this->hasOne(User::className(), ['id' => 'id_user']); | |||
} | |||
public function getProducer() | |||
{ | |||
return $this->hasOne(Producer::className(), ['id' => 'id_producer']); | |||
} | |||
public function relationOrders($fieldIdDocument) | |||
{ | |||
$defaultOptionsSearch = Order::defaultOptionsSearch(); | |||
return $this->hasMany(Order::className(), [$fieldIdDocument => 'id']) | |||
->with($defaultOptionsSearch['with']) | |||
->joinWith($defaultOptionsSearch['join_with']) | |||
->orderBy('distribution.date ASC'); | |||
} | |||
/* | |||
* Méthodes | |||
*/ | |||
public function getAmount($type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($type, false, $format); | |||
} | |||
public function getAmountWithTax($type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($type, true, $format); | |||
} | |||
protected function _getAmountGeneric($type = Order::AMOUNT_TOTAL, $withTax = true, $format = false) | |||
{ | |||
$amount = 0; | |||
$totalVat = 0; | |||
$ordersArray = $this->orders; | |||
foreach ($ordersArray as $order) { | |||
$order->init($this->tax_calculation_method); | |||
$amount += $order->getAmount($type); | |||
$totalVat += $order->getTotalVat($type); | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'name' => 'Nom', | |||
'reference' => 'Référence', | |||
'date' => 'Date', | |||
'comment' => 'Commentaire', | |||
'id_user' => 'Utilisateur', | |||
'address' => 'Adresse', | |||
'id_producer' => 'Producteur', | |||
'status' => 'Statut', | |||
]; | |||
if ($this->isTaxCalculationMethodRoundingOfTheSum()) { | |||
$totalVat = Price::round($totalVat); | |||
} | |||
/* | |||
* Relations | |||
*/ | |||
public function getUser() | |||
{ | |||
return $this->hasOne(User::className(), ['id' => 'id_user']); | |||
} | |||
public function getProducer() | |||
{ | |||
return $this->hasOne(Producer::className(), ['id' => 'id_producer']); | |||
if ($withTax) { | |||
$amount += $totalVat; | |||
} | |||
public function relationOrders($fieldIdDocument) | |||
{ | |||
$defaultOptionsSearch = Order::defaultOptionsSearch(); | |||
return $this->hasMany(Order::className(), [$fieldIdDocument => 'id']) | |||
->with($defaultOptionsSearch['with']) | |||
->joinWith($defaultOptionsSearch['join_with']) | |||
->orderBy('distribution.date ASC'); | |||
if ($format) { | |||
return Price::format($amount); | |||
} else { | |||
return $amount; | |||
} | |||
} | |||
public function getTotalVatArray($typeTotal) | |||
{ | |||
$totalVatArray = []; | |||
/* | |||
* Méthodes | |||
*/ | |||
$ordersArray = $this->orders; | |||
public function getAmount($type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($type, false, $format); | |||
} | |||
public function getAmountWithTax($type = Order::AMOUNT_TOTAL, $format = false) | |||
{ | |||
return $this->_getAmountGeneric($type, true, $format); | |||
foreach ($ordersArray as $order) { | |||
$order->init($this->tax_calculation_method); | |||
$fieldNameVat = $order->getFieldNameAmount($typeTotal, 'vat'); | |||
foreach ($order->$fieldNameVat as $idTaxRate => $vat) { | |||
if (!isset($totalVatArray[$idTaxRate])) { | |||
$totalVatArray[$idTaxRate] = 0; | |||
} | |||
$totalVatArray[$idTaxRate] += $vat; | |||
} | |||
} | |||
protected function _getAmountGeneric($type = Order::AMOUNT_TOTAL, $withTax = true, $format = false) | |||
{ | |||
$amount = 0; | |||
$ordersArray = $this->orders; | |||
return $totalVatArray; | |||
} | |||
foreach ($ordersArray as $order) { | |||
$order->init(); | |||
if ($withTax) { | |||
$amount += $order->getAmountWithTax($type); | |||
} | |||
else { | |||
$amount += $order->getAmount($type); | |||
} | |||
} | |||
if ($format) { | |||
return Price::format($amount); | |||
} else { | |||
return $amount; | |||
} | |||
public function getPointSale() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->pointSale; | |||
} else { | |||
return ''; | |||
} | |||
public function getPointSale() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->pointSale; | |||
} else { | |||
return ''; | |||
} | |||
} | |||
public function getDistribution() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->distribution; | |||
} else { | |||
return ''; | |||
} | |||
public function getDistribution() | |||
{ | |||
if (isset($this->orders) && isset($this->orders[0])) { | |||
return $this->orders[0]->distribution; | |||
} else { | |||
return ''; | |||
} | |||
} | |||
public function getClass() | |||
{ | |||
return str_replace('common\models\\', '', get_class($this)); | |||
} | |||
public function getType() | |||
{ | |||
$class = $this->getClass(); | |||
if ($class == 'Invoice') { | |||
$documentType = 'Facture'; | |||
} elseif ($class == 'DeliveryNote') { | |||
$documentType = 'Bon de livraison'; | |||
} elseif ($class == 'Quotation') { | |||
$documentType = 'Devis'; | |||
} | |||
public function getClass() | |||
{ | |||
return str_replace('common\models\\', '', get_class($this)); | |||
if (isset($documentType)) { | |||
return $documentType; | |||
} | |||
public function getType() | |||
{ | |||
$class = $this->getClass(); | |||
if ($class == 'Invoice') { | |||
$documentType = 'Facture'; | |||
} elseif ($class == 'DeliveryNote') { | |||
$documentType = 'Bon de livraison'; | |||
} elseif ($class == 'Quotation') { | |||
$documentType = 'Devis'; | |||
} | |||
return ''; | |||
} | |||
if (isset($documentType)) { | |||
return $documentType; | |||
} | |||
public function isValidClass($typeDocument) | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); | |||
} | |||
return ''; | |||
public function generateReference() | |||
{ | |||
$class = $this->getClass(); | |||
$classLower = strtolower($class); | |||
if ($classLower == 'deliverynote') { | |||
$classLower = 'delivery_note'; | |||
} | |||
public function isValidClass($typeDocument) | |||
{ | |||
return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); | |||
$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 generateReference() | |||
{ | |||
$class = $this->getClass(); | |||
$classLower = strtolower($class); | |||
if ($classLower == 'deliverynote') { | |||
$classLower = 'delivery_note'; | |||
} | |||
public function downloadPdf() | |||
{ | |||
$filenameComplete = $this->getFilenameComplete(); | |||
$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'; | |||
} | |||
} | |||
if(!file_exists($filenameComplete)) { | |||
$this->generatePdf(Pdf::DEST_FILE); | |||
} | |||
public function generatePdf($destination) | |||
{ | |||
$producer = GlobalParam::getCurrentProducer(); | |||
$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 ; | |||
} | |||
$pdf = new Pdf([ | |||
'mode' => Pdf::MODE_UTF8, | |||
'format' => Pdf::FORMAT_A4, | |||
'orientation' => Pdf::ORIENT_PORTRAIT, | |||
'destination' => $destination, | |||
'content' => $content, | |||
'filename' => $this->getFilename(), | |||
'cssFile' => Yii::getAlias('@webroot/css/document/download.css'), | |||
'marginBottom' => $marginBottom, | |||
'methods' => [ | |||
'SetHTMLFooter' => $contentFooter | |||
] | |||
]); | |||
return $pdf->render(); | |||
if(file_exists($filenameComplete)) { | |||
return Yii::$app->response->sendFile($filenameComplete, $this->getFilename(), ['inline'=>true]); | |||
} | |||
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->getFilename()); | |||
return $email->send() ; | |||
} | |||
return false ; | |||
else { | |||
throw new ErrorException('File '.$filenameComplete.' not found'); | |||
} | |||
public function changeStatus($status) | |||
{ | |||
if ($status == Document::STATUS_VALID) { | |||
$this->status = $status; | |||
$this->reference = $this->generateReference(); | |||
} | |||
public function generatePdf($destination) | |||
{ | |||
$producer = GlobalParam::getCurrentProducer(); | |||
$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>'; | |||
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>'; | |||
$marginBottom = 10; | |||
if (strlen(Producer::getConfig('document_infos_bottom')) > 0) { | |||
$marginBottom = 40; | |||
} | |||
public function isStatus($status) | |||
{ | |||
return $this->status == $status; | |||
$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(); | |||
} | |||
public function isStatusDraft() | |||
{ | |||
return $this->isStatus(self::STATUS_DRAFT); | |||
} | |||
return false; | |||
} | |||
public function isStatusValid() | |||
{ | |||
return $this->isStatus(self::STATUS_VALID); | |||
public function changeStatus($status) | |||
{ | |||
if ($status == Document::STATUS_VALID) { | |||
$this->status = $status; | |||
$this->reference = $this->generateReference(); | |||
} | |||
public function getProductsOrders() | |||
{ | |||
$productsOrdersArray = []; | |||
$ordersArray = $this->orders ; | |||
if ($ordersArray && count($ordersArray)) { | |||
foreach ($ordersArray as $order) { | |||
foreach ($order->productOrder as $productOrder) { | |||
$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 | |||
&& ( (!$this->isInvoicePrice() && $theProductOrder->price == $productOrder->price) | |||
|| ($this->isInvoicePrice() && $theProductOrder->invoice_price == $productOrder->invoice_price) | |||
)) { | |||
$theProductOrder->quantity += $productOrder->quantity; | |||
$productOrderMatch = true; | |||
} | |||
} | |||
if (!$productOrderMatch) { | |||
$productsOrdersArray[$indexProductOrder][] = $newProductOrder; | |||
} | |||
} | |||
} | |||
} | |||
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) { | |||
$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 | |||
&& ((!$this->isInvoicePrice() && $theProductOrder->price == $productOrder->price) | |||
|| ($this->isInvoicePrice() && $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); | |||
// tri des orderProduct par product.order | |||
ksort($productsOrdersArray); | |||
return $productsOrdersArray; | |||
} | |||
return $productsOrdersArray; | |||
} | |||
public function isDisplayOrders() | |||
{ | |||
$displayOrders = ($this->getClass() == 'Invoice') ? | |||
Producer::getConfig('document_display_orders_invoice') : | |||
Producer::getConfig('document_display_orders_delivery_note') ; | |||
public function isDisplayOrders() | |||
{ | |||
$displayOrders = ($this->getClass() == 'Invoice') ? | |||
Producer::getConfig('document_display_orders_invoice') : | |||
Producer::getConfig('document_display_orders_delivery_note'); | |||
return $displayOrders ; | |||
} | |||
return $displayOrders; | |||
} | |||
public function getFilename() | |||
{ | |||
return Yii::getAlias('@app/web/pdf/'.$this->getType().'-' . $this->reference. '.pdf') ; | |||
} | |||
public function getAliasDirectoryBase() | |||
{ | |||
return '@app/web/pdf/'.$this->id_producer.'/'; | |||
} | |||
public function isInvoicePrice() | |||
{ | |||
return $this->getClass() == 'Invoice' || $this->getClass() == 'DeliveryNote' ; | |||
public function initDirectoryPdf() | |||
{ | |||
$aliasDirectoryBase = $this->getAliasDirectoryBase(); | |||
$directoryPdf = Yii::getAlias($aliasDirectoryBase); | |||
if(!file_exists($directoryPdf)) { | |||
mkdir($directoryPdf, 0755); | |||
} | |||
} | |||
public function getFilename() | |||
{ | |||
return $this->getType() . '-' . $this->reference . '.pdf'; | |||
} | |||
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,8 +63,10 @@ class Order extends ActiveRecordCommon | |||
{ | |||
var $amount = 0; | |||
var $amount_with_tax = 0; | |||
var $amount_vat = []; | |||
var $invoice_amount = 0; | |||
var $invoice_amount_with_tax = 0; | |||
var $invoice_amount_vat = []; | |||
var $paid_amount = 0; | |||
var $weight = 0; | |||
@@ -223,9 +225,9 @@ class Order extends ActiveRecordCommon | |||
* Initialise le montant total, le montant déjà payé et le poids de la | |||
* commande. | |||
*/ | |||
public function init() | |||
public function init($taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT) | |||
{ | |||
$this->initAmount(); | |||
$this->initAmount($taxCalculationMethod); | |||
$this->initPaidAmount(); | |||
return $this; | |||
@@ -235,46 +237,90 @@ class Order extends ActiveRecordCommon | |||
* Initialise le montant de la commande. | |||
* | |||
*/ | |||
public function initAmount() | |||
public function initAmount($taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT) | |||
{ | |||
$this->amount = 0; | |||
$this->amount_with_tax = 0; | |||
$this->amount_vat = []; | |||
$this->invoice_amount = 0; | |||
$this->invoice_amount_with_tax = 0; | |||
$this->invoice_amount_vat = []; | |||
$this->weight = 0; | |||
if (isset($this->productOrder)) { | |||
foreach ($this->productOrder as $productOrder) { | |||
$this->amount += $productOrder->price * $productOrder->quantity; | |||
$this->amount_with_tax += Price::getPriceWithTax( | |||
$productOrder->price, | |||
$productOrder->taxRate->value | |||
) * $productOrder->quantity; | |||
if($productOrder->invoice_price) { | |||
$invoicePrice = $productOrder->invoice_price; | |||
} | |||
else { | |||
$invoicePrice = $productOrder->price; | |||
} | |||
$this->invoice_amount += $invoicePrice * $productOrder->quantity; | |||
$this->invoice_amount_with_tax += Price::getPriceWithTax( | |||
$invoicePrice, | |||
$productOrder->taxRate->value | |||
) * $productOrder->quantity; | |||
$this->addAmount(self::AMOUNT_TOTAL, $productOrder, $taxCalculationMethod); | |||
$this->addAmount(self::INVOICE_AMOUNT_TOTAL, $productOrder, $taxCalculationMethod); | |||
$this->addWeight($productOrder); | |||
} | |||
} | |||
} | |||
if ($productOrder->unit == 'piece') { | |||
if (isset($productOrder->product)) { | |||
$this->weight += ($productOrder->quantity * $productOrder->product->weight) / 1000; | |||
} | |||
} else { | |||
$this->weight += $productOrder->quantity; | |||
} | |||
public function addWeight($productOrder) | |||
{ | |||
if ($productOrder->unit == 'piece') { | |||
if (isset($productOrder->product)) { | |||
$this->weight += ($productOrder->quantity * $productOrder->product->weight) / 1000; | |||
} | |||
} else { | |||
$this->weight += $productOrder->quantity; | |||
} | |||
} | |||
public function addAmount($typeTotal, $productOrder, $taxCalculationMethod) | |||
{ | |||
$fieldNameAmount = $this->getFieldNameAmount($typeTotal); | |||
$fieldNameAmountWithTax = $this->getFieldNameAmount($typeTotal, 'with_tax'); | |||
$price = $productOrder->getPriceByTypeTotal($typeTotal); | |||
$this->$fieldNameAmount += $price * $productOrder->quantity; | |||
$this->$fieldNameAmountWithTax += Price::getPriceWithTax( | |||
$price, | |||
$productOrder->taxRate->value, | |||
$taxCalculationMethod | |||
) * $productOrder->quantity; | |||
$this->addVat($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); | |||
} | |||
public function getTotalVat($typeTotal = self::AMOUNT_TOTAL) | |||
{ | |||
$fieldName = $this->getFieldNameAmount($typeTotal, 'vat'); | |||
$totalVat = 0; | |||
foreach($this->$fieldName as $vat) { | |||
$totalVat += $vat; | |||
} | |||
return $totalVat; | |||
} | |||
public function getFieldNameAmount($typeTotal = self::AMOUNT_TOTAL, $typeField = '') | |||
{ | |||
$fieldName = 'amount'; | |||
if($typeTotal == self::INVOICE_AMOUNT_TOTAL) { | |||
$fieldName = 'invoice_amount'; | |||
} | |||
if($typeField == 'vat') { | |||
$fieldName = $fieldName.'_vat'; | |||
} | |||
elseif($typeField == 'with_tax') { | |||
$fieldName = $fieldName.'_with_tax'; | |||
} | |||
return $fieldName; | |||
} | |||
/** | |||
* Initialise le montant payé de la commande et le retourne. | |||
* |
@@ -98,6 +98,24 @@ class Producer extends ActiveRecordCommon | |||
const ORDER_ENTRY_POINT_DATE = 'date'; | |||
const ORDER_ENTRY_POINT_POINT_SALE = 'point-sale'; | |||
const BILLING_FREQUENCY_MONTHLY = 'monthly'; | |||
const BILLING_FREQUENCY_QUARTERLY = 'quarterly'; | |||
const BILLING_FREQUENCY_BIANNUAL = 'biannual'; | |||
public static $billingFrequencyArray = [ | |||
self::BILLING_FREQUENCY_MONTHLY => 'Mensuelle', | |||
self::BILLING_FREQUENCY_QUARTERLY => 'Trimestrielle', | |||
self::BILLING_FREQUENCY_BIANNUAL => 'Biannuelle', | |||
]; | |||
const BILLING_TYPE_CLASSIC = 'classic'; | |||
const BILLING_TYPE_FREE_PRICE = 'free-price'; | |||
public static $billingTypeArray = [ | |||
self::BILLING_TYPE_CLASSIC => 'Classique', | |||
self::BILLING_TYPE_FREE_PRICE => 'Prix libre', | |||
]; | |||
var $secret_key_payplug; | |||
/** | |||
@@ -205,7 +223,8 @@ class Producer extends ActiveRecordCommon | |||
'option_stripe_public_key', | |||
'option_stripe_private_key', | |||
'option_stripe_endpoint_secret', | |||
'option_online_payment_type' | |||
'option_online_payment_type', | |||
'option_tax_calculation_method' | |||
], | |||
'string' | |||
], | |||
@@ -232,7 +251,9 @@ class Producer extends ActiveRecordCommon | |||
'option_delivery', | |||
'option_display_export_grid', | |||
'option_stripe_mode_test', | |||
'option_notify_producer_order_summary' | |||
'option_notify_producer_order_summary', | |||
'option_billing_reduction', | |||
'option_export_evoliz' | |||
], | |||
'boolean' | |||
], | |||
@@ -253,7 +274,9 @@ class Producer extends ActiveRecordCommon | |||
'document_invoice_prefix', | |||
'document_invoice_first_reference', | |||
'document_delivery_note_prefix', | |||
'document_delivery_note_first_reference' | |||
'document_delivery_note_first_reference', | |||
'option_billing_type', | |||
'option_billing_frequency', | |||
], | |||
'string', | |||
'max' => 255 | |||
@@ -267,7 +290,6 @@ class Producer extends ActiveRecordCommon | |||
'type' => 'number', | |||
'message' => 'Prix libre doit être supérieur ou égal à 0' | |||
], | |||
//[['option_dashboard_date_start', 'option_dashboard_date_end'], 'date', 'format' => 'php:d/m/Y'], | |||
[['option_dashboard_date_start', 'option_dashboard_date_end'], 'safe'], | |||
]; | |||
} | |||
@@ -363,7 +385,12 @@ class Producer extends ActiveRecordCommon | |||
'option_delivery' => 'Proposer la livraison à domicile', | |||
'option_display_export_grid' => 'Afficher l\'export grille dans les distributions', | |||
'document_display_product_description' => 'Documents : afficher la description des produits', | |||
'option_notify_producer_order_summary' => 'Recevoir les récapitulatifs de commande par email' | |||
'option_notify_producer_order_summary' => 'Recevoir les récapitulatifs de commande par email', | |||
'option_billing_type' => 'Type de facturation', | |||
'option_billing_frequency' => 'Fréquence de facturation', | |||
'option_billing_reduction' => 'Réduction appliquée au moment de la facturation', | |||
'option_tax_calculation_method' => 'Méthode de calcul de la TVA', | |||
'option_export_evoliz' => 'Activer l\'export vers Evoliz' | |||
]; | |||
} | |||
@@ -491,6 +518,82 @@ class Producer extends ActiveRecordCommon | |||
} | |||
} | |||
public function getAmountToBeBilledByTurnover($turnover, $format = false) | |||
{ | |||
$amountToBeBilled = 0; | |||
$producerPriceRangeArray = ProducerPriceRange::find()->all(); | |||
foreach($producerPriceRangeArray as $priceRange) { | |||
if($turnover >= $priceRange->range_begin && $turnover < $priceRange->range_end) { | |||
$amountToBeBilled = $priceRange->price; | |||
} | |||
} | |||
if($format) { | |||
return Price::format($amountToBeBilled); | |||
} | |||
else { | |||
return $amountToBeBilled; | |||
} | |||
} | |||
public function getAmountToBeBilledByMonth($month, $format = false) | |||
{ | |||
$turnover = $this->getTurnover($month); | |||
return $this->getAmountToBeBilledByTurnover($turnover, $format); | |||
} | |||
public function getSummaryAmountsToBeBilled($label, $numberOfMonths = 1) | |||
{ | |||
$text = ''; | |||
$numMonthCurrent = date('m'); | |||
if($numberOfMonths == 1 | |||
|| ($numberOfMonths == 3 && (in_array($numMonthCurrent, [1, 4, 7, 10]))) | |||
|| ($numberOfMonths == 6 && (in_array($numMonthCurrent, [1, 7])))) { | |||
for ($i = 1; $i <= $numberOfMonths; $i++) { | |||
$month = date('Y-m', strtotime('-' . $i . ' month')); | |||
$turnover = $this->getTurnover($month); | |||
if ($turnover) { | |||
if ($this->isBillingTypeClassic()) { | |||
$text .= '<strong>'; | |||
} | |||
$text .= $this->getAmountToBeBilledByTurnover($turnover, true); | |||
if ($this->isBillingTypeClassic()) { | |||
$text .= '</strong>'; | |||
} | |||
$text .= ' / '.Price::format($turnover); | |||
$text .= '<br />'; | |||
} | |||
} | |||
if (strlen($text)) { | |||
$text = $label . ' : <br />' . $text; | |||
} | |||
} | |||
return $text; | |||
} | |||
public function getAmountBilledLastMonth() | |||
{ | |||
if($this->isBillingTypeClassic()) { | |||
$month = date('Y-m', strtotime('-1 month')); | |||
return $this->getAmountToBeBilledByMonth($month); | |||
} | |||
elseif($this->isBillingTypeFreePrice()) { | |||
return $this->free_price; | |||
} | |||
return 0; | |||
} | |||
/** | |||
* Retourne le montant à facturer pour une période donnée. | |||
* | |||
@@ -572,7 +675,7 @@ class Producer extends ActiveRecordCommon | |||
{ | |||
if (!is_null($this->free_price)) { | |||
if ($format) { | |||
return number_format($this->free_price, 2, ',', false) . ' € HT'; | |||
return number_format($this->free_price, 2, ',', false) . ' €'; | |||
} else { | |||
return $this->free_price; | |||
} | |||
@@ -832,5 +935,39 @@ class Producer extends ActiveRecordCommon | |||
return $this->isOnlinePaymentActive() && $this->option_online_payment_type == 'order' ; | |||
} | |||
public static function getBillingFrequencyPopulateDropdown() | |||
{ | |||
return self::$billingFrequencyArray; | |||
} | |||
public function isBillingFrequencyMonthly() | |||
{ | |||
return $this->option_billing_frequency == self::BILLING_FREQUENCY_MONTHLY; | |||
} | |||
public function isBillingFrequencyQuarterly() | |||
{ | |||
return $this->option_billing_frequency == self::BILLING_FREQUENCY_QUARTERLY; | |||
} | |||
public function isBillingFrequencyBiannual() | |||
{ | |||
return $this->option_billing_frequency == self::BILLING_FREQUENCY_BIANNUAL; | |||
} | |||
public static function getBillingTypePopulateDropdown() | |||
{ | |||
return self::$billingTypeArray; | |||
} | |||
public function isBillingTypeClassic() | |||
{ | |||
return $this->option_billing_type == self::BILLING_TYPE_CLASSIC; | |||
} | |||
public function isBillingTypeFreePrice() | |||
{ | |||
return $this->option_billing_type == self::BILLING_TYPE_FREE_PRICE; | |||
} | |||
} | |||
@@ -0,0 +1,95 @@ | |||
<?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. | |||
*/ | |||
namespace common\models; | |||
use common\components\ActiveRecordCommon; | |||
/** | |||
* This is the model class for table "producer_price_range". | |||
* | |||
* @property integer $id | |||
*/ | |||
class ProducerPriceRange extends ActiveRecordCommon | |||
{ | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'producer_price_range'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['range_begin', 'range_end', 'price'], 'double'], | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'range_begin' => 'Début', | |||
'range_end' => 'Fin', | |||
'price' => 'Tarif (HT)', | |||
]; | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => [], | |||
'join_with' => [], | |||
'orderby' => '', | |||
'attribute_id_producer' => '' | |||
]; | |||
} | |||
} |
@@ -149,4 +149,13 @@ class ProductOrder extends ActiveRecordCommon | |||
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; | |||
} | |||
} |
@@ -58,4 +58,16 @@ class TaxRate extends ActiveRecordCommon | |||
'attribute_id_producer' => '' | |||
] ; | |||
} | |||
public static function getTaxRateArray() | |||
{ | |||
$taxRateArrayReturn = []; | |||
$taxRateArray = TaxRate::find()->all(); | |||
foreach($taxRateArray as $taxRate) { | |||
$taxRateArrayReturn[$taxRate->id] = $taxRate; | |||
} | |||
return $taxRateArrayReturn; | |||
} | |||
} |
@@ -105,7 +105,7 @@ class User extends ActiveRecordCommon implements IdentityInterface | |||
{ | |||
return [ | |||
[['no_mail', 'mail_distribution_monday', 'mail_distribution_tuesday', 'mail_distribution_wednesday', 'mail_distribution_thursday', 'mail_distribution_friday', 'mail_distribution_saturday', 'mail_distribution_sunday', 'is_main_contact'], 'boolean'], | |||
[['lastname', 'name', 'phone', 'address', 'type', 'name_legal_person'], 'string'], | |||
[['lastname', 'name', 'phone', 'address', 'type', 'name_legal_person', 'evoliz_code'], 'string'], | |||
['lastname', 'verifyOneName', 'skipOnError' => false, 'skipOnEmpty' => false], | |||
['email', 'email', 'message' => 'Cette adresse email n\'est pas valide'], | |||
['email', 'verifyEmail'], | |||
@@ -145,7 +145,8 @@ class User extends ActiveRecordCommon implements IdentityInterface | |||
'name_legal_person' => 'Libellé', | |||
'is_main_contact' => 'Contact principal', | |||
'product_price_percent' => 'Prix produits : pourcentage', | |||
'user_groups' => "Groupes d'utilisateurs" | |||
'user_groups' => "Groupes d'utilisateurs", | |||
'evoliz_code' => 'Code client Evoliz' | |||
]; | |||
} | |||
@@ -0,0 +1,31 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
/** | |||
* Class m220914_091112_add_table_producer_price_range | |||
*/ | |||
class m220914_091112_add_table_producer_price_range extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->createTable('producer_price_range', [ | |||
'id' => 'pk', | |||
'range_begin' => Schema::TYPE_DOUBLE . ' NOT NULL', | |||
'range_end' => Schema::TYPE_DOUBLE, | |||
'price' => Schema::TYPE_DOUBLE . ' NOT NULL', | |||
]); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropTable('producer_price_range'); | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
use common\models\Producer; | |||
/** | |||
* Class m220915_072309_producer_add_option_billing_frequency | |||
*/ | |||
class m220915_072309_producer_add_option_billing_frequency extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->addColumn('producer', 'option_billing_frequency', Schema::TYPE_STRING.' DEFAULT \''.Producer::BILLING_FREQUENCY_MONTHLY.'\''); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('producer','option_billing_frequency'); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
use common\models\Producer; | |||
/** | |||
* Class m220915_083713_producer_add_options_billing | |||
*/ | |||
class m220915_083713_producer_add_options_billing extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->addColumn('producer', 'option_billing_type', Schema::TYPE_STRING.' DEFAULT \''.Producer::BILLING_TYPE_CLASSIC.'\''); | |||
$this->addColumn('producer', 'option_billing_reduction', Schema::TYPE_BOOLEAN.' DEFAULT 0'); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('producer','option_billing_type'); | |||
$this->dropColumn('producer','option_billing_reduction'); | |||
} | |||
} |
@@ -0,0 +1,44 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
use common\models\Document; | |||
/** | |||
* Class m220916_062206_add_column_document_tax_calculation_method | |||
*/ | |||
class m220916_062206_add_column_document_tax_calculation_method extends Migration | |||
{ | |||
public static $tableDocumentArray = ['invoice', 'delivery_note', 'quotation']; | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$schemaTaxCalculationMethod = Schema::TYPE_STRING.' DEFAULT \''.Document::TAX_CALCULATION_METHOD_DEFAULT.'\''; | |||
// producer | |||
$this->addColumn('producer', 'option_tax_calculation_method', $schemaTaxCalculationMethod); | |||
// documents | |||
$columnTaxCalculationMethod = 'tax_calculation_method'; | |||
foreach(self::$tableDocumentArray as $tableName) { | |||
$this->addColumn($tableName, $columnTaxCalculationMethod, $schemaTaxCalculationMethod); | |||
// méthode appliquée jusqu'à maintenant | |||
$this->execute('UPDATE `'.$tableName.'` SET `'.$columnTaxCalculationMethod.'` = \''.Document::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS.'\''); | |||
} | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('producer', 'option_tax_calculation_method'); | |||
foreach(self::$tableDocumentArray as $tableName) { | |||
$this->dropColumn($tableName, 'tax_calculation_method'); | |||
} | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
/** | |||
* Class m220919_084020_add_fields_export_evoliz | |||
*/ | |||
class m220919_084020_add_fields_export_evoliz extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->addColumn('producer', 'option_export_evoliz', Schema::TYPE_BOOLEAN .' DEFAULT 0'); | |||
$this->addColumn('user', 'evoliz_code', Schema::TYPE_STRING); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('producer', 'option_export_evoliz'); | |||
$this->dropColumn('user', 'evoliz_code'); | |||
} | |||
} |