Skip to content

Commit

Permalink
1635: Reduced product invoice entries to a single entry
Browse files Browse the repository at this point in the history
  • Loading branch information
rimi-itk committed Jun 12, 2024
1 parent 6455a04 commit 87eb3ca
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 23 deletions.
4 changes: 3 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ PRODUCT_QUANTITY_SCALE=2
# },
# "product": {
# "label": "The real PSP element",
# "product": true
# "product": true,
# // Optional invoice entry product name prefix
# "invoice_entry_prefix": "Tryk"
# }
# }'
#
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* [PR-130](https://github.com/itk-dev/economics/pull/130)
1635: Reduced product invoice entries to a single entry
* NOTE: APP_DEFAULT_PLANNING_DATA_PROVIDER has been changed to APP_DEFAULT_DATA_PROVIDER. This has to be changed when releasing.
* [PR-117](https://github.com/itk-dev/economics/pull/117)
1211: Added hour report
Expand Down
11 changes: 11 additions & 0 deletions src/Service/InvoiceEntryHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ public function getAccountLabel(string $account): string
return $accounts[$account]['label'] ?? $account;
}

/**
* Get account invoice entry pretix based on configured accounts.
*/
public function getAccountInvoiceEntryPrefix(string $account): ?string
{
$accounts = $this->getAccounts(null);

return $accounts[$account]['invoice_entry_prefix'] ?? null;
}

/**
* Decide if an invoice entry is editable.
*/
Expand Down Expand Up @@ -127,6 +137,7 @@ private function resolveOptions(array $options): array
->setDefaults([
'default' => false,
'product' => false,
'invoice_entry_prefix' => null,
])
->setAllowedTypes('default', 'bool')
->setAllowedTypes('product', 'bool');
Expand Down
62 changes: 40 additions & 22 deletions src/Service/ProjectBillingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Entity\Invoice;
use App\Entity\InvoiceEntry;
use App\Entity\Issue;
use App\Entity\IssueProduct;
use App\Entity\ProjectBilling;
use App\Entity\Worklog;
use App\Enum\ClientTypeEnum;
Expand Down Expand Up @@ -180,6 +181,23 @@ public function createProjectBilling(int $projectBillingId): void
}
}

$defaultAccount = $this->invoiceEntryHelper->getDefaultAccount();
$productAccount = $this->invoiceEntryHelper->getProductAccount();

// Add invoice entry account prefix, if any, to (product) name.
$prefixWithAccount = function (?string $account, ?string $name): ?string {
if (null === $name) {
return null;
}

$prefix = $account ? $this->invoiceEntryHelper->getAccountInvoiceEntryPrefix($account) : null;
if (null !== $prefix) {
$name = $prefix.': '.$name;
}

return $name;
};

foreach ($invoices as $invoiceArray) {
/** @var Client $client */
$client = $invoiceArray['client'];
Expand All @@ -198,15 +216,18 @@ public function createProjectBilling(int $projectBillingId): void

// TODO: MaterialNumberEnum::EXTERNAL_WITH_MOMS or MaterialNumberEnum::EXTERNAL_WITHOUT_MOMS?
$invoice->setDefaultMaterialNumber($internal ? MaterialNumberEnum::INTERNAL : MaterialNumberEnum::EXTERNAL_WITH_MOMS);
$invoice->setDefaultReceiverAccount($this->invoiceEntryHelper->getDefaultAccount());
$invoice->setDefaultReceiverAccount($defaultAccount);

/** @var Issue $issue */
foreach ($invoiceArray['issues'] as $issue) {
$invoiceEntry = new InvoiceEntry();
$invoiceEntry->setEntryType(InvoiceEntryTypeEnum::WORKLOG);
$invoiceEntry->setDescription('');

$product = $this->getInvoiceEntryProduct($issue);
$product = $prefixWithAccount(
$defaultAccount,
$this->getInvoiceEntryProduct($issue)
);
$price = $this->clientHelper->getStandardPrice($client);

$invoiceEntry->setProduct($product);
Expand Down Expand Up @@ -236,29 +257,26 @@ public function createProjectBilling(int $projectBillingId): void
$this->entityManager->persist($invoiceEntry);
}

$invoiceEntryProductName = $invoiceEntry->getProduct();
// Add invoice entries for each product.
foreach ($issue->getProducts() as $productIssue) {
$product = $productIssue->getProduct();
if (null === $product) {
continue;
}

$productName = $product->getName() ?? '';
// Add a single product entry summing all product expenses.
$products = $issue->getProducts();
if (!$products->isEmpty()) {
$price = $products->reduce(static fn (?float $sum, IssueProduct $product) => $sum + $product->getTotal(), 0.0);
$product = $prefixWithAccount(
$productAccount,
$issue->getName()
);
$productInvoiceEntry = (new InvoiceEntry())
->setEntryType(InvoiceEntryTypeEnum::PRODUCT)
->setDescription($productIssue->getDescription())
->setProduct(null === $invoiceEntryProductName
? $productName
: sprintf('%s: %s', $invoiceEntryProductName, $productName)
)
->setPrice($product->getPriceAsFloat())
->setAmount($productIssue->getQuantity())
->setTotalPrice($productIssue->getQuantity() * $product->getPriceAsFloat())
->setDescription($issue->getName())
->setProduct($product)
->setPrice($price)
->setAmount(1)
->setTotalPrice($price)
->setMaterialNumber($invoice->getDefaultMaterialNumber())
->setAccount($this->invoiceEntryHelper->getProductAccount()
?? $this->invoiceEntryHelper->getDefaultAccount())
->addIssueProduct($productIssue);
->setAccount($productAccount ?? $this->invoiceEntryHelper->getDefaultAccount());
foreach ($issue->getProducts() as $productIssue) {
$productInvoiceEntry->addIssueProduct($productIssue);
}
// We don't add worklogs here, since they're already attached to the main invoice entry
// (and only used to detect if an entry has been added to an invoice).

Expand Down

0 comments on commit 87eb3ca

Please sign in to comment.