I'm working on an Angular app that uses OroCommerce & angular2-jsonapi
to interface with the Oro frontend API.
It's worked well so far, but now I need to create an order
object from my UI and the POST request is failing.
Here are my object models:
@JsonApiModelConfig({
type: 'orderlineitems',
})
export class OrderLineItem extends JsonApiModel {
@Attribute()
public id: string;
@Attribute()
public price: string;
@Attribute()
public quantity: string;
@Attribute()
public productName: string;
@Attribute()
public productSku: string;
@Attribute()
public productUnit: string;
@BelongsTo()
public product: ProductSummary;
}
@JsonApiModelConfig({
type: 'orderaddresses',
})
export class OrderAddress extends JsonApiModel {
@Attribute()
public id: string;
@Attribute()
public city: string;
@Attribute()
public firstName: string;
@Attribute()
public lastName: string;
@Attribute()
public organization: string;
@Attribute()
public postalCode: string;
@Attribute()
public street: string;
@Attribute()
public country: string;
@Attribute()
public region: string;
}
@JsonApiModelConfig({
type: 'orders',
})
export class Order extends JsonApiModel {
@Attribute()
public id: string;
@Attribute()
public totalValue: string;
@Attribute()
public createdAt: Date;
@Attribute()
public updatedAt: Date;
@Attribute()
public paymentStatus: { code: PaymentStatusCodes, label: string };
@Attribute()
public paymentMethod: { code: string, label: string }[];
@BelongsTo()
public billingAddress: OrderAddress; // this is missing in request Payload
@BelongsTo()
public shippingAddress: OrderAddress; // this is missing in request Payload
@BelongsTo()
public customer: object;
@BelongsTo()
public customerUser: CustomerUser;
@HasMany()
public lineItems: OrderLineItem;
}
And here's the code making the actual request to datastore.createRecord()
:
public createOrder(): Observable<Order> {
const orderAddress = new OrderAddress(this.datastore, {
city: 'Grenoble',
firstName: 'John',
lastName: 'Doe',
organization: 'MyOrg',
postalCode: '38000',
street: '123 main street',
country: 'FR',
region: 'Isère',
});
const lineItem = new OrderLineItem(this.datastore, {
quantity: '1',
productUnit: 'each',
});
const newOrder = this.datastore.createRecord(Order, {
owner: '1',
customer: '34',
customerUser: '34',
currency: 'EUR',
paymentStatus: {
code: PaymentStatusCodes.pending,
label: 'lab1'
},
paymentMethod: {
code: 'payment_term_1',
label: 'payment_term_1'
},
lineItems: [lineItem, lineItem],
billingAddress: orderAddress, // addresses added here
shippingAddress: orderAddress, // addresses added here
});
return newOrder.save().pipe(
map((data) => {
return data;
}),
catchError(errorResponse => {
if (errorResponse instanceof ErrorResponse) {
return throwError(errorResponse.errors[0]);
}
return throwError(this.errorService.getRelevantMessage(errorResponse));
})
);
}
As you can see I am including the fields billingAddress
& shippingAddress
, but the request fails with a 400 :
{
"errors":[
{
"status":"400",
"title":"not blank constraint",
"detail":"This value should not be blank.",
"source":{
"pointer":"\/data\/relationships\/billingAddress\/data"
}
},
{
"status":"400",
"title":"not blank constraint",
"detail":"This value should not be blank.",
"source":{
"pointer":"\/data\/relationships\/shippingAddress\/data"
}
},
{
"status":"400",
"title":"count constraint",
"detail":"Please add at least one Line Item",
"source":{
"pointer":"\/data\/relationships\/lineItems\/data"
}
}
]
}
When I look at the Payload section of my browser, I see that indeed neither of the addresses are added to the Payload...
Any help appreciated!
From the code you shared it seems that neither OrderAddress
nor OrderLineItem
has been created at the server before creating Order
.
The OroCommerce Web Services API, which you are integrating with, implements the JSON:API specification. The JSON:API specification does not support creating multiple resources in a single request. This is only supported if implementing the Atomic Operations extension.
The Atomic Operations extension is relatively new. The OroCommerce team has come up with a custom solution to create primary resource together with related resources in a single request. It uses client-generated IDs together with a Compound Document for the request payload. While this solves the need, it is not compliant with the JSON:API specification.
Without knowing many details about angular2-jsonapi, I assume that it does not support this custom solution OroCommerce came up with. Instead it seems to skip resources, which have not been created yet, when serializing a record as a JSON:API resource object.