Accounting/Export/AccountingExporter.php
protected function writeInvoiceGoodsLines()
    {
        $sale = $this->invoice->getSale();
        $date = $sale->getCreatedAt();
        $taxRule = $this->taxResolver->resolveSaleTaxRule($sale);
        /** @var \Ekyna\Component\Commerce\Common\Model\AdjustmentInterface[] $discounts */
        $discounts = $sale->getAdjustments(AdjustmentTypes::TYPE_DISCOUNT)->toArray();

        // Gather amounts by tax rates
        $amounts = [];
        foreach ($this->invoice->getLinesByType(DocumentLineTypes::TYPE_GOOD) as $line) {
            // Skip private lines
            if ($line->getSaleItem()->isPrivate()) {
                continue;
            }

            $rates = $line->getTaxRates();
            if (empty($rates)) {
                $rate = 0;
            } elseif (1 === count($rates)) {
                $rate = current($rates);
            } else {
                throw new LogicException("Multiple tax rates on goods lines are not yet supported."); // TODO
            }

            $amount = $line->getBase();

            // Apply sale's discounts
            if (!empty($discounts)) {
                $base = $amount;
                foreach ($discounts as $adjustment) {
                    if ($adjustment->getMode() === AdjustmentModes::MODE_PERCENT) {
                        $amount -= $this->round($amount * $adjustment->getAmount() / 100);
                    } else {
                        $amount -= $this->round($base / $this->invoice->getGoodsBase() * $adjustment->getAmount());
                    }
                }
            }

            if (!isset($amounts[(string)$rate])) {
                $amounts[(string)$rate] = 0;
            }

            $amounts[(string)$rate] += $this->round($amount);
        }

        $credit = $this->invoice->getType() === InvoiceTypes::TYPE_CREDIT;

        // Writes each tax rates's amount
        foreach ($amounts as $rate => $amount) {
            $amount = $this->round($amount);

            if (0 === $this->compare($amount, 0)) {
                continue; // next tax rate
            }

            $account = $this->getGoodAccountNumber($taxRule, (float)$rate, $this->invoice->getNumber());

            if ($credit) {
                $this->writer->credit($account, (string)$amount, $date);
                $this->balance -= $amount;
            } else {
                $this->writer->debit($account, (string)$amount, $date);
                $this->balance += $amount;
            }
        }
    }
protected function writeInvoiceGoodsLines()
    {
        $sale = $this->invoice->getSale();
        $date = $sale->getCreatedAt();
        $taxRule = $this->taxResolver->resolveSaleTaxRule($sale);
        /** @var \Ekyna\Component\Commerce\Common\Model\AdjustmentInterface[] $discounts */
        $discounts = $sale->getAdjustments(AdjustmentTypes::TYPE_DISCOUNT)->toArray();

        // Gather amounts by tax rates
        $amounts = [];
        foreach ($this->invoice->getLinesByType(DocumentLineTypes::TYPE_GOOD) as $line) {
            // Skip private lines
            if ($line->getSaleItem()->isPrivate()) {
                continue;
            }

            $rates = $line->getTaxRates();
            if (empty($rates)) {
                $rate = 0;
            } elseif (1 === count($rates)) {
                $rate = current($rates);
            } else {
                throw new LogicException("Multiple tax rates on goods lines are not yet supported."); // TODO
            }

            $amount = $line->getBase();

            // Apply sale's discounts
            if (!empty($discounts)) {
                $base = $amount;
                foreach ($discounts as $adjustment) {
                    if ($adjustment->getMode() === AdjustmentModes::MODE_PERCENT) {
                        $amount -= $this->round($amount * $adjustment->getAmount() / 100);
                    } else {
                        $amount -= $this->round($base / $this->invoice->getGoodsBase() * $adjustment->getAmount());
                    }
                }
            }

            if (!isset($amounts[(string)$rate])) {
                $amounts[(string)$rate] = 0;
            }

            $amounts[(string)$rate] += $this->round($amount);
        }

        $credit = $this->invoice->getType() === InvoiceTypes::TYPE_CREDIT;

        // Writes each tax rates's amount
        foreach ($amounts as $rate => $amount) {
            $amount = $this->round($amount);

            if (0 === $this->compare($amount, 0)) {
                continue; // next tax rate
            }

            $account = $this->getGoodAccountNumber($taxRule, (float)$rate, $this->invoice->getNumber());

            if ($credit) {
                $this->writer->credit($account, (string)$amount, $date);
                $this->balance -= $amount;
            } else {
                $this->writer->debit($account, (string)$amount, $date);
                $this->balance += $amount;
            }
        }
    }
Writes the invoice's goods line.