Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OBPIH-3799, OBPIH-3840 Generate Invoice for PO after prepayment #2412

Merged
merged 2 commits into from
May 19, 2021

Conversation

awalkowiak
Copy link
Collaborator

No description provided.

@awalkowiak awalkowiak requested a review from jmiranda May 18, 2021 17:06
@@ -256,9 +256,9 @@ class UrlMappings {
}

// Invoice API
"/api/invoices/$id/invoiceItems"(parseRequest: true) {
"/api/invoices/$id/items"(parseRequest: true) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting chose. Can/should we apply this to other APIs in the near future?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should if we can specify the same endpoint for different request methods. In this case we had two separate endpoints for no reason.

@@ -95,4 +95,15 @@ class InvoiceController {
Invoice invoice = invoiceService.generatePrepaymentInvoice(order)
redirect(action: "create", params: [id: invoice.id])
}

def generateInvoiceAfterPrepayment = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can just be generateInvoice().

@@ -69,7 +69,7 @@ class Invoice implements Serializable {
invoiceItems cascade: "all-delete-orphan"
}

static transients = ['vendorInvoiceNumber', 'totalValue', 'totalValueNormalized', 'documents', 'status']
static transients = ['vendorInvoiceNumber', 'totalValue', 'totalValueNormalized', 'documents', 'status', 'hasPrepaymentAssociated']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to hasPrepaymentInvoice to keep it consistent.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But technically invoice does not have prepayment invoice (order does)

ShipmentItem getShipmentItem() {
return shipmentItems ? shipmentItems?.iterator()?.next() : null
OrderItem getOrderItem() {
return orderItems ? orderItems?.find { it } : null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the switch? I can see why it might help (choose the first non-null item) but do we think it'll ever be null?

Copy link
Collaborator Author

@awalkowiak awalkowiak May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was more for IDE to get rid of underscore warning

OrderItem getOrderItem() {
if (orderAdjustments) {
return orderAdjustment?.orderItem
Order getOrder() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method scares me the most. I think I'd prefer to leave it up to the developer unless it causes us to write this branching logic whenever we need to access Order.

If we do need it, perhaps since a shipment might include multiple orders we always return a list of Orders here to make sure our Invoice model exposes the right method signature. It would be bad if the system supported adding multiple orders per shipment / invoice, but the model itself did not.

List<Order> getOrders() { 
    return orderItem ? [orderItem.order] : orderAdjustment ? [orderAdjustment.order] : shipmentItem.orderItems*.order
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll investigate it with other refactors, so this can be tested

@@ -175,8 +174,8 @@ class InvoiceItem implements Serializable {
Map toJson() {
return [
id: id,
orderNumber: orderNumber,
shipmentNumber: shipmentNumber,
orderNumber: order?.orderNumber ?: '',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why empty string here and not null?

left join shipment_invoice on shipment_invoice.shipment_item_id = shipment_item.id
where shipment_invoice.invoice_item_id is null and shipment.current_status = 'SHIPPED');
where order_invoice.invoice_item_id is null and shipment_invoice.invoice_item_id is null and shipment.current_status = 'SHIPPED');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each condition of the where clause should be on a separate line for readability.

invoice.invoiceType = InvoiceType.findByCode(InvoiceTypeCode.PREPAYMENT_INVOICE)
createOrUpdateVendorInvoiceNumber(invoice, order.orderNumber + Constants.PREPAYMENT_INVOICE_SUFFIX)

if (order.orderItems.size() + order.orderAdjustments.size() == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Careful here. I think Hibernate/Grails will initialize the orderItems and orderAdjustments with an empty list, but for unit tests it might not so you'll need to add null safety.

Plus I would suggest using something more readable like this.

if (!order?.orderItems?.empty && !order?.orderAdjustments?.empty)

Copy link
Collaborator Author

@awalkowiak awalkowiak May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the tip

@@ -171,14 +171,22 @@
${warehouse.message(code: 'default.button.rollback.label')}
</g:link>
<g:if test="${!orderInstance?.hasInvoice && orderInstance?.paymentTerm?.prepaymentPercent &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should encapsulate this logic in a domain method. In fact, I think we use each component in other places so let's add methods for each of them.

Boolean isPrepaymentInvoiceAllowed() { 
    return !this.hasInvoice && this.isPrepaymentRequired && !this.empty()
}

Boolean isPrepaymentRequired() { 
    return this.paymentTerm?.prepaymentPercent > 0
}

Boolean isEmpty() { 
    return this.orderItems?.empty && orderInstance?.orderAdjustments?.empty
}

I can't remember the convention for is/has methods in Grails, so you might have to play around with isSomeCondition() vs getIsSomeCondition().

And isEmpty is not descriptive enough so please suggest a more descriptive name if you can think of one. The following is a little long and awkward, but descriptive.

isOrderItemsAndOrderAdjustmentsEmpty

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll tackle it with refactors for Order.getInvoiceItems

@pmuchowski pmuchowski merged commit 8a110ae into develop May 19, 2021
@pmuchowski pmuchowski deleted the OBPIH-3799 branch May 19, 2021 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants