class InvoiceGenerator in Commerce Invoice 8.2
Hierarchy
- class \Drupal\commerce_invoice\InvoiceGenerator implements InvoiceGeneratorInterface
Expanded class hierarchy of InvoiceGenerator
1 string reference to 'InvoiceGenerator'
1 service uses InvoiceGenerator
File
- src/
InvoiceGenerator.php, line 17
Namespace
Drupal\commerce_invoiceView source
class InvoiceGenerator implements InvoiceGeneratorInterface {
/**
* The database connection to use.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
*/
protected $entityTypeManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a new InvoiceGenerator object.
*
* @param \Drupal\Core\Database\Connection $connection
* The database connection to use.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(Connection $connection, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler) {
$this->connection = $connection;
$this->entityTypeManager = $entity_type_manager;
$this->languageManager = $language_manager;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public function generate(array $orders, StoreInterface $store, ProfileInterface $profile = NULL, array $values = [], $save = TRUE) {
$transaction = $this->connection
->startTransaction();
try {
return $this
->doGenerate($orders, $store, $profile, $values, $save);
} catch (\Exception $exception) {
$transaction
->rollBack();
watchdog_exception('commerce_invoice', $exception);
return NULL;
}
}
/**
* @see \Drupal\commerce_invoice\InvoiceGeneratorInterface::generate()
*/
protected function doGenerate(array $orders, StoreInterface $store, ProfileInterface $profile = NULL, array $values = [], $save = TRUE) {
$invoice_storage = $this->entityTypeManager
->getStorage('commerce_invoice');
$values += [
'store_id' => $store
->id(),
'billing_profile' => $profile,
];
// If we're not generating an invoice for a single order, don't inherit its
// customer information and payment method.
if (count($orders) !== 1) {
$values += [
'mail' => NULL,
'uid' => NULL,
'payment_method' => NULL,
];
}
// Assume the order type from the first passed order, we'll use it
// to determine the invoice type to create.
/** @var \Drupal\commerce_order\Entity\OrderInterface $first_order */
$first_order = reset($orders);
/** @var \Drupal\commerce_invoice\Entity\InvoiceInterface $invoice */
$invoice = $invoice_storage
->createFromOrder($first_order, $values);
// Find any (partial) invoices that reference the given orders so we can
// subtract their adjustments and invoice items quantities and adjustments.
$existing_invoices = $invoice_storage
->loadByOrders($invoice
->bundle(), $orders);
$total_paid = NULL;
/** @var \Drupal\commerce_order\Entity\OrderInterface[] $orders */
foreach ($orders as $order) {
$existing_invoices_for_order = array_filter($existing_invoices, function (InvoiceInterface $invoice) use ($order) {
$order_ids = array_column($invoice
->get('orders')
->getValue(), 'target_id');
return in_array($order
->id(), $order_ids);
});
// Copy over all the adjustments from the order, if there any left after
// taking into account those that were applied to previous invoices.
foreach ($this
->getAdjustmentsFromEntity($order, $existing_invoices_for_order) as $adjustment) {
$invoice
->addAdjustment($adjustment);
}
foreach ($this
->getInvoiceItemsFromOrder($order, $invoice, $existing_invoices_for_order) as $invoice_item) {
if ($save) {
$invoice_item
->save();
}
$invoice
->addItem($invoice_item);
}
$total_paid = $total_paid ? $total_paid
->add($order
->getTotalPaid()) : $order
->getTotalPaid();
}
if ($total_paid) {
$invoice
->setTotalPaid($total_paid);
}
$invoice
->setOrders($orders);
if ($invoice
->getState()
->getId() === 'draft') {
$invoice
->getState()
->applyTransitionById('confirm');
}
if ($save) {
$invoice
->save();
}
return $invoice;
}
/**
* Return an array of adjustments from a given adjustable entity.
*
* @param \Drupal\commerce_order\EntityAdjustableInterface $entity
* An adjustable entity object.
* @param \Drupal\commerce_order\EntityAdjustableInterface[] $existing_items
* (optional) An array of existing items that might contain adjustments
* which need to be subtracted from adjustable entity above. Defaults to an
* empty array.
*
* @return \Drupal\commerce_order\Adjustment[]
* An array of adjustments.
*/
private function getAdjustmentsFromEntity(EntityAdjustableInterface $entity, array $existing_items = []) {
$adjustments = [];
foreach ($entity
->getAdjustments() as $adjustment) {
// Look through all the existing invoices for this order and subtract the
// amount of their adjustments.
foreach ($existing_items as $existing_item) {
foreach ($existing_item
->getAdjustments() as $previous_adjustment) {
if ($adjustment
->getType() === $previous_adjustment
->getType() && $adjustment
->getSourceId() === $previous_adjustment
->getSourceId()) {
$adjustment = $adjustment
->subtract($previous_adjustment);
}
}
}
if (!$adjustment
->getAmount()
->isZero()) {
$adjustments[] = $adjustment;
}
}
return $adjustments;
}
/**
* Return an array of invoice items from a given order.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* The order.
* @param \Drupal\commerce_invoice\Entity\InvoiceInterface $invoice
* An invoice.
* @param \Drupal\commerce_invoice\Entity\InvoiceInterface[] $existing_invoices
* (optional) An array of existing (partial) invoices for this order.
* Defaults to an empty array.
*
* @return \Drupal\commerce_invoice\Entity\InvoiceItemInterface[]
* An array of invoice items.
*/
private function getInvoiceItemsFromOrder(OrderInterface $order, InvoiceInterface $invoice, array $existing_invoices = []) {
$invoice_items = [];
// Get the default invoice language so we can set it on invoice items.
$default_langcode = $invoice
->language()
->getId();
$invoice_item_storage = $this->entityTypeManager
->getStorage('commerce_invoice_item');
foreach ($order
->getItems() as $order_item) {
/** @var \Drupal\commerce_order\Entity\OrderItemTypeInterface $order_item_type */
$order_item_type = OrderItemType::load($order_item
->bundle());
$invoice_item_type = $order_item_type
->getPurchasableEntityTypeId() ?: 'default';
/** @var \Drupal\commerce_invoice\Entity\InvoiceItemInterface $invoice_item */
$invoice_item = $invoice_item_storage
->create([
'langcode' => $default_langcode,
'type' => $invoice_item_type,
]);
$invoice_item
->populateFromOrderItem($order_item);
// Look through all the existing invoices for this order and subtract the
// quantity of their matching invoice items. We don't need to this for
// each invoice item translation below because
// InvoiceItem::populateFromOrderItem() only sets the quantity value on
// the default translation.
foreach ($existing_invoices as $existing_invoice) {
foreach ($existing_invoice
->getItems() as $previous_invoice_item) {
if ($invoice_item
->getOrderItemId() == $previous_invoice_item
->getOrderItemId()) {
$new_quantity = Calculator::subtract($invoice_item
->getQuantity(), $previous_invoice_item
->getQuantity());
$invoice_item
->setQuantity($new_quantity);
}
}
}
// Ensure that order items that have corresponding quantity value in the
// existing (partial) invoices can not be added to a new invoice.
if (Calculator::compare($invoice_item
->getQuantity(), '0') == 0) {
continue;
}
// Look through all the existing invoices for this order and subtract the
// adjustments of their matching invoice items.
$previous_invoice_items = [];
foreach ($existing_invoices as $existing_invoice) {
$previous_invoice_items = array_merge($previous_invoice_items, array_filter($existing_invoice
->getItems(), function ($previous_invoice_item) use ($invoice_item) {
return $invoice_item
->getOrderItemId() == $previous_invoice_item
->getOrderItemId();
}));
}
$invoice_item
->setAdjustments($this
->getAdjustmentsFromEntity($order_item, $previous_invoice_items));
// If the invoice is translated, we need to generate translations in
// all languages for each invoice item.
foreach ($invoice
->getTranslationLanguages(FALSE) as $langcode => $language) {
$translated_invoice_item = $invoice_item
->addTranslation($langcode);
// We're calling InvoiceItem::populateFromOrderItem() for each
// translation since that logic is responsible for pulling the
// translated variation title, if available.
$translated_invoice_item
->populateFromOrderItem($order_item);
}
$invoice_items[] = $invoice_item;
}
return $invoice_items;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
InvoiceGenerator:: |
protected | property | The database connection to use. | |
InvoiceGenerator:: |
protected | property | The entity type manager. | |
InvoiceGenerator:: |
protected | property | The language manager. | |
InvoiceGenerator:: |
protected | property | The module handler. | |
InvoiceGenerator:: |
protected | function | ||
InvoiceGenerator:: |
public | function |
Generates an invoice for the given orders. Overrides InvoiceGeneratorInterface:: |
|
InvoiceGenerator:: |
private | function | Return an array of adjustments from a given adjustable entity. | |
InvoiceGenerator:: |
private | function | Return an array of invoice items from a given order. | |
InvoiceGenerator:: |
public | function | Constructs a new InvoiceGenerator object. |