|  | @@ -2,19 +2,14 @@
 | 
		
	
		
			
			| 2 | 2 |  
 | 
		
	
		
			
			| 3 | 3 |  namespace App\View\Models;
 | 
		
	
		
			
			| 4 | 4 |  
 | 
		
	
		
			
			| 5 |  | -use App\Enums\Accounting\AdjustmentComputation;
 | 
		
	
		
			
			| 6 |  | -use App\Enums\Accounting\DocumentDiscountMethod;
 | 
		
	
		
			
			| 7 | 5 |  use App\Enums\Accounting\DocumentType;
 | 
		
	
		
			
			| 8 |  | -use App\Models\Accounting\Adjustment;
 | 
		
	
		
			
			| 9 | 6 |  use App\Models\Accounting\DocumentLineItem;
 | 
		
	
		
			
			| 10 | 7 |  use App\Models\Common\Client;
 | 
		
	
		
			
			| 11 | 8 |  use App\Models\Company;
 | 
		
	
		
			
			| 12 | 9 |  use App\Models\Setting\DocumentDefault;
 | 
		
	
		
			
			| 13 | 10 |  use App\Utilities\Currency\CurrencyAccessor;
 | 
		
	
		
			
			| 14 | 11 |  use App\Utilities\Currency\CurrencyConverter;
 | 
		
	
		
			
			| 15 |  | -use App\Utilities\RateCalculator;
 | 
		
	
		
			
			| 16 | 12 |  use Illuminate\Database\Eloquent\Model;
 | 
		
	
		
			
			| 17 |  | -use Illuminate\Support\Number;
 | 
		
	
		
			
			| 18 | 13 |  
 | 
		
	
		
			
			| 19 | 14 |  class DocumentPreviewViewModel
 | 
		
	
		
			
			| 20 | 15 |  {
 | 
		
	
	
		
			
			|  | @@ -120,85 +115,4 @@ class DocumentPreviewViewModel
 | 
		
	
		
			
			| 120 | 115 |              'show_logo' => $settings->show_logo ?? false,
 | 
		
	
		
			
			| 121 | 116 |          ];
 | 
		
	
		
			
			| 122 | 117 |      }
 | 
		
	
		
			
			| 123 |  | -
 | 
		
	
		
			
			| 124 |  | -    private function calculateLineSubtotalInCents(array $item, string $currencyCode): int
 | 
		
	
		
			
			| 125 |  | -    {
 | 
		
	
		
			
			| 126 |  | -        $quantity = max((float) ($item['quantity'] ?? 0), 0);
 | 
		
	
		
			
			| 127 |  | -        $unitPrice = max((float) ($item['unit_price'] ?? 0), 0);
 | 
		
	
		
			
			| 128 |  | -
 | 
		
	
		
			
			| 129 |  | -        $subtotal = $quantity * $unitPrice;
 | 
		
	
		
			
			| 130 |  | -
 | 
		
	
		
			
			| 131 |  | -        return CurrencyConverter::convertToCents($subtotal, $currencyCode);
 | 
		
	
		
			
			| 132 |  | -    }
 | 
		
	
		
			
			| 133 |  | -
 | 
		
	
		
			
			| 134 |  | -    private function calculateAdjustmentsTotalInCents($lineItems, string $key, string $currencyCode): int
 | 
		
	
		
			
			| 135 |  | -    {
 | 
		
	
		
			
			| 136 |  | -        return $lineItems->reduce(function ($carry, $item) use ($key, $currencyCode) {
 | 
		
	
		
			
			| 137 |  | -            $quantity = max((float) ($item['quantity'] ?? 0), 0);
 | 
		
	
		
			
			| 138 |  | -            $unitPrice = max((float) ($item['unit_price'] ?? 0), 0);
 | 
		
	
		
			
			| 139 |  | -            $adjustmentIds = $item[$key] ?? [];
 | 
		
	
		
			
			| 140 |  | -            $lineTotal = $quantity * $unitPrice;
 | 
		
	
		
			
			| 141 |  | -
 | 
		
	
		
			
			| 142 |  | -            $lineTotalInCents = CurrencyConverter::convertToCents($lineTotal, $currencyCode);
 | 
		
	
		
			
			| 143 |  | -
 | 
		
	
		
			
			| 144 |  | -            $adjustmentTotal = Adjustment::whereIn('id', $adjustmentIds)
 | 
		
	
		
			
			| 145 |  | -                ->get()
 | 
		
	
		
			
			| 146 |  | -                ->sum(function (Adjustment $adjustment) use ($lineTotalInCents) {
 | 
		
	
		
			
			| 147 |  | -                    if ($adjustment->computation->isPercentage()) {
 | 
		
	
		
			
			| 148 |  | -                        return RateCalculator::calculatePercentage($lineTotalInCents, $adjustment->getRawOriginal('rate'));
 | 
		
	
		
			
			| 149 |  | -                    } else {
 | 
		
	
		
			
			| 150 |  | -                        return $adjustment->getRawOriginal('rate');
 | 
		
	
		
			
			| 151 |  | -                    }
 | 
		
	
		
			
			| 152 |  | -                });
 | 
		
	
		
			
			| 153 |  | -
 | 
		
	
		
			
			| 154 |  | -            return $carry + $adjustmentTotal;
 | 
		
	
		
			
			| 155 |  | -        }, 0);
 | 
		
	
		
			
			| 156 |  | -    }
 | 
		
	
		
			
			| 157 |  | -
 | 
		
	
		
			
			| 158 |  | -    private function calculateDiscountTotalInCents($lineItems, int $subtotalInCents, string $currencyCode): int
 | 
		
	
		
			
			| 159 |  | -    {
 | 
		
	
		
			
			| 160 |  | -        $discountMethod = DocumentDiscountMethod::parse($this->data['discount_method']) ?? DocumentDiscountMethod::PerLineItem;
 | 
		
	
		
			
			| 161 |  | -
 | 
		
	
		
			
			| 162 |  | -        if ($discountMethod->isPerLineItem()) {
 | 
		
	
		
			
			| 163 |  | -            return $this->calculateAdjustmentsTotalInCents($lineItems, $this->documentType->getDiscountKey(), $currencyCode);
 | 
		
	
		
			
			| 164 |  | -        }
 | 
		
	
		
			
			| 165 |  | -
 | 
		
	
		
			
			| 166 |  | -        $discountComputation = AdjustmentComputation::parse($this->data['discount_computation']) ?? AdjustmentComputation::Percentage;
 | 
		
	
		
			
			| 167 |  | -        $discountRate = blank($this->data['discount_rate']) ? '0' : $this->data['discount_rate'];
 | 
		
	
		
			
			| 168 |  | -
 | 
		
	
		
			
			| 169 |  | -        if ($discountComputation->isPercentage()) {
 | 
		
	
		
			
			| 170 |  | -            $scaledDiscountRate = RateCalculator::parseLocalizedRate($discountRate);
 | 
		
	
		
			
			| 171 |  | -
 | 
		
	
		
			
			| 172 |  | -            return RateCalculator::calculatePercentage($subtotalInCents, $scaledDiscountRate);
 | 
		
	
		
			
			| 173 |  | -        }
 | 
		
	
		
			
			| 174 |  | -
 | 
		
	
		
			
			| 175 |  | -        if (! CurrencyConverter::isValidAmount($discountRate)) {
 | 
		
	
		
			
			| 176 |  | -            $discountRate = '0';
 | 
		
	
		
			
			| 177 |  | -        }
 | 
		
	
		
			
			| 178 |  | -
 | 
		
	
		
			
			| 179 |  | -        return CurrencyConverter::convertToCents($discountRate, $currencyCode);
 | 
		
	
		
			
			| 180 |  | -    }
 | 
		
	
		
			
			| 181 |  | -
 | 
		
	
		
			
			| 182 |  | -    private function buildConversionMessage(int $grandTotalInCents, string $currencyCode, string $defaultCurrencyCode): ?string
 | 
		
	
		
			
			| 183 |  | -    {
 | 
		
	
		
			
			| 184 |  | -        if ($currencyCode === $defaultCurrencyCode) {
 | 
		
	
		
			
			| 185 |  | -            return null;
 | 
		
	
		
			
			| 186 |  | -        }
 | 
		
	
		
			
			| 187 |  | -
 | 
		
	
		
			
			| 188 |  | -        $rate = currency($currencyCode)->getRate();
 | 
		
	
		
			
			| 189 |  | -        $indirectRate = 1 / $rate;
 | 
		
	
		
			
			| 190 |  | -
 | 
		
	
		
			
			| 191 |  | -        $convertedTotalInCents = CurrencyConverter::convertBalance($grandTotalInCents, $currencyCode, $defaultCurrencyCode);
 | 
		
	
		
			
			| 192 |  | -
 | 
		
	
		
			
			| 193 |  | -        $formattedRate = Number::format($indirectRate, maxPrecision: 10);
 | 
		
	
		
			
			| 194 |  | -
 | 
		
	
		
			
			| 195 |  | -        return sprintf(
 | 
		
	
		
			
			| 196 |  | -            'Currency conversion: %s (%s) at an exchange rate of 1 %s = %s %s',
 | 
		
	
		
			
			| 197 |  | -            CurrencyConverter::formatCentsToMoney($convertedTotalInCents, $defaultCurrencyCode),
 | 
		
	
		
			
			| 198 |  | -            $defaultCurrencyCode,
 | 
		
	
		
			
			| 199 |  | -            $currencyCode,
 | 
		
	
		
			
			| 200 |  | -            $formattedRate,
 | 
		
	
		
			
			| 201 |  | -            $defaultCurrencyCode
 | 
		
	
		
			
			| 202 |  | -        );
 | 
		
	
		
			
			| 203 |  | -    }
 | 
		
	
		
			
			| 204 | 118 |  }
 |