'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'], ['is_sent', 'boolean'], [['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', 'is_sent' => 'Envoyé' ]; } /* * 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; // Méthode de calcul via les commandes liées /*foreach ($ordersArray as $order) { $order->init($this->tax_calculation_method); $amount += $order->getAmount($type); $totalVat += $order->getTotalVat($type); }*/ // Méthode de calcul via getProductOrders() foreach($this->getProductsOrders() as $productOrderArray) { foreach($productOrderArray as $productOrder) { $priceLine = $productOrder->getPriceByTypeTotal($type) * $productOrder->quantity; $amount += $priceLine; $totalVat += Price::getVat($priceLine, $productOrder->taxRate->value, $this->tax_calculation_method); } } if ($this->isTaxCalculationMethodRoundingOfTheSum()) { $totalVat = Price::round($totalVat); } if ($withTax) { $amount += $totalVat; } if ($format) { return Price::format($amount); } else { return $amount; } } public function getTotalVatArray($typeTotal) { $totalVatArray = []; // Méthode de calcul via les commandes liées /*$ordersArray = $this->orders; 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; } }*/ // Méthode de calcul via getProductOrders() foreach($this->getProductsOrders() as $productOrderArray) { foreach ($productOrderArray as $productOrder) { $idTaxRate = $productOrder->taxRate->id; if (!isset($totalVatArray[$idTaxRate])) { $totalVatArray[$idTaxRate] = 0; } $totalVatArray[$idTaxRate] += Price::getVat( $productOrder->getPriceByTypeTotal($typeTotal) * $productOrder->quantity, $productOrder->taxRate->value, $this->tax_calculation_method ); } } return $totalVatArray; } 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 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'; } if (isset($documentType)) { return $documentType; } return ''; } public function isValidClass($typeDocument) { return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']); } public function generateReference() { $class = $this->getClass(); $classLower = strtolower($class); if ($classLower == 'deliverynote') { $classLower = 'delivery_note'; } $prefix = Producer::getConfig('document_' . $classLower . '_prefix'); $oneDocumentExist = $class::searchOne(['status' => Document::STATUS_VALID], ['orderby' => 'reference DESC']); if ($oneDocumentExist) { $reference = $oneDocumentExist->reference; $pattern = '#([A-Z]+)?([0-9]+)#'; preg_match($pattern, $reference, $matches, PREG_OFFSET_CAPTURE); $sizeNumReference = strlen($matches[2][0]); $numReference = ((int)$matches[2][0]) + 1; $numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT); return $prefix . $numReference; } else { $firstReference = Producer::getConfig('document_' . $classLower . '_first_reference'); if (strlen($firstReference) > 0) { return $firstReference; } else { return $prefix . '00001'; } } } public function downloadPdf() { $filenameComplete = $this->getFilenameComplete(); if (!file_exists($filenameComplete)) { $this->generatePdf(Pdf::DEST_FILE); } if (file_exists($filenameComplete)) { return Yii::$app->response->sendFile($filenameComplete, $this->getFilename(), ['inline' => true]); } else { throw new ErrorException('File ' . $filenameComplete . ' not found'); } } public function generatePdf($destination) { $producer = $this->producer; $content = Yii::$app->controller->renderPartial('/document/download', [ 'producer' => $producer, 'document' => $this ]); $contentFooter = ''; $marginBottom = 10; if (strlen(Producer::getConfig('document_infos_bottom')) > 0) { $marginBottom = 40; } $this->initDirectoryPdf(); $pdf = new Pdf([ 'mode' => Pdf::MODE_UTF8, 'format' => Pdf::FORMAT_A4, 'orientation' => Pdf::ORIENT_PORTRAIT, 'destination' => $destination, 'content' => $content, 'filename' => $this->getFilenameComplete(), 'cssFile' => Yii::getAlias('@webroot/css/document/download.css'), 'marginBottom' => $marginBottom, 'methods' => [ 'SetHTMLFooter' => $contentFooter ] ]); return $pdf->render(); } public function send() { if (isset($this->user) && strlen($this->user->email) > 0) { $producer = GlobalParam::getCurrentProducer(); $subjectEmail = $this->getType(); if ($this->isStatusValid()) { $subjectEmail .= ' N°' . $this->reference; } $email = Yii::$app->mailer->compose( [ 'html' => 'sendDocument-html', 'text' => 'sendDocument-text' ], [ 'document' => $this, ]) ->setTo($this->user->email) ->setFrom([$producer->getEmailOpendistrib() => $producer->name]) ->setSubject('[' . $producer->name . '] ' . $subjectEmail); $this->generatePdf(Pdf::DEST_FILE); $email->attach($this->getFilenameComplete()); return $email->send(); } return false; } public function changeStatus($status) { if ($status == Document::STATUS_VALID) { $this->status = $status; $this->reference = $this->generateReference(); } } public function getStatusWording() { return ($this->status == self::STATUS_DRAFT) ? 'Brouillon' : 'Validé'; } public function getStatusCssClass() { return ($this->status == self::STATUS_DRAFT) ? 'default' : 'success'; } public function getHtmlLabel() { $label = $this->getStatusWording(); $classLabel = $this->getStatusCssClass(); return '' . $label . ''; } public function isStatus($status) { return $this->status == $status; } public function isStatusDraft() { return $this->isStatus(self::STATUS_DRAFT); } public function isStatusValid() { return $this->isStatus(self::STATUS_VALID); } public function getProductsOrders() { $productsOrdersArray = []; $ordersArray = $this->orders; if ($ordersArray && count($ordersArray)) { foreach ($ordersArray as $order) { foreach ($order->productOrder as $productOrder) { if ($productOrder->product) { $indexProductOrder = $productOrder->product->order; $newProductOrder = clone $productOrder; if (!isset($productsOrdersArray[$indexProductOrder])) { $productsOrdersArray[$indexProductOrder] = [$newProductOrder]; } else { $productOrderMatch = false; foreach ($productsOrdersArray[$indexProductOrder] as &$theProductOrder) { if ($theProductOrder->unit == $productOrder->unit && $theProductOrder->price == $productOrder->price && $theProductOrder->invoice_price == $productOrder->invoice_price) { $theProductOrder->quantity += $productOrder->quantity; $productOrderMatch = true; } } if (!$productOrderMatch) { $productsOrdersArray[$indexProductOrder][] = $newProductOrder; } } } } } } // tri des orderProduct par product.order ksort($productsOrdersArray); return $productsOrdersArray; } public function isDisplayOrders() { $displayOrders = ($this->getClass() == 'Invoice') ? Producer::getConfig('document_display_orders_invoice') : Producer::getConfig('document_display_orders_delivery_note'); return $displayOrders; } public function getAliasDirectoryBase() { return '@app/web/pdf/' . $this->id_producer . '/'; } public function initDirectoryPdf() { $aliasDirectoryBase = $this->getAliasDirectoryBase(); $directoryPdf = Yii::getAlias($aliasDirectoryBase); if (!file_exists($directoryPdf)) { mkdir($directoryPdf, 0755); } } public function getFilename() { $filename = $this->getType() . '-'; if($this->isStatusValid()) { $filename .= $this->reference; } elseif($this->isStatusDraft()) { $filename .= 'Brouillon-'.$this->id; } $filename .= '.pdf'; return $filename; } public function getFilenameComplete() { return Yii::getAlias($this->getAliasDirectoryBase() . $this->getFilename()); } public function isInvoicePrice() { return $this->getClass() == 'Invoice' || $this->getClass() == 'DeliveryNote'; } public function isTaxCalculationMethodSumOfRoundings() { return $this->tax_calculation_method == self::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS; } public function isTaxCalculationMethodRoundingOfTheSum() { return $this->tax_calculation_method == self::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM; } public function initTaxCalculationMethod() { $producerTaxCalculationMethod = Producer::getConfig('option_tax_calculation_method'); if ($producerTaxCalculationMethod) { $this->tax_calculation_method = $producerTaxCalculationMethod; } else { $this->tax_calculation_method = self::TAX_CALCULATION_METHOD_DEFAULT; } } }