I’m sending a Sales Order with Pre-Authorized Payment thru REST API in Acumatica. This works perfect in my local Acumatica instance. However, I can’t get it worked when switching to Acumatica.com and I’m getting this error “The order cannot be applied, the specified combination of the order type and order number cannot be found in the system.”. It works well when I remove the payment details.
<pre><code>
{
"BillToAddress": {
"AddressLine1": {
"value": "3153 Doctors Drive"
},
"AddressLine2": {
"value": ""
},
"City": {
"value": "Los Angeles"
},
"Country": {
"value": "US"
},
"PostalCode": {
"value": "90017"
},
"State": {
"value": "CA"
},
"custom": {}
},
"BillToAddressOverride": {
"value": false
},
"BillToContact": {
"Attention": {
"value": "Mr."
},
"BusinessName": {
"value": "Gregory Luton"
},
"Email": {
"value": "gluton#hotmeal.com"
},
"Phone1": {
"value": "(310) 341-3975"
},
"custom": {}
},
"CreditHold": {
"value": false
},
"CustomerID": {
"value": "S000000001"
},
"CustomerOrder": {},
"Date": {
"value": "2021-06-02T13:42:02.22Z"
},
"Description": {
"value": ""
},
"Details": [
{
"ManualPrice": {
"value": true
},
"Amount": {
"value": 79.99
},
"DiscountAmount": {
"value": 0
},
"DiscountCode": {},
"DiscountPercent": {
"value": 0
},
"ExtendedPrice": {
"value": 79.99
},
"FreeItem": {
"value": false
},
"InventoryID": {
"value": "ELEHDD1"
},
"LineDescription": {
"value": "Lego 500 piece set"
},
"LineNbr": {
"value": 1
},
"ManualDiscount": {
"value": false
},
"OpenQty": {
"value": 1
},
"OrderQty": {
"value": 1
},
"RequestedOn": {
"value": "2021-06-02T13:42:02.22Z"
},
"Subitem": {
"value": ""
},
"UnbilledAmount": {
"value": 79.99
},
"UnitPrice": {
"value": 79.99
},
"UOM": {
"value": "EA"
},
"WarehouseID": {
"value": "WHOLESALE"
},
"rowNumber": 1,
"custom": {}
}
],
"Hold": {
"value": false
},
"OrderedQty": {
"value": 1
},
"OrderTotal": {
"value": 79.99
},
"OrderType": {
"value": "SO"
},
"Payments": [
{
"CardAccountNbr": {
"value": "CUSTOMPAYMC:S000000001"
},
"CashAccount": {
"value": "10600"
},
"CreditCardTransactionInfo": [
{
"AuthNbr": {
"value": "23456"
},
"NeedValidation": {
"value": false
},
"TranDate": {
"value": "2021-06-02T16:13:01.22Z"
},
"TranNbr": {
"value": "12345"
},
"TranType": {
"value": "Authorize Only"
},
"custom": {}
}
],
"Description": {
"value": "Payment for 006024"
},
"PaymentAmount": {
"value": 79.99
},
"PaymentMethod": {
"value": "CUSTOMPAYMC"
},
"ProcessingCenterID": {
"value": "CUSTOMPAY"
},
"Status": {
"value": "Pre-Authorized"
},
"custom": {}
}
],
"RequestedOn": {
"value": "2021-06-02T13:42:02.22Z"
},
"ShipToAddress": {
"AddressLine1": {},
"AddressLine2": {},
"City": {},
"Country": {},
"PostalCode": {},
"State": {},
"custom": {}
},
"ShipToAddressOverride": {
"value": false
},
"ShipToContact": {
"Attention": {},
"BusinessName": {},
"Email": {},
"Phone1": {},
"custom": {}
},
"ShipVia": {
"value": ""
},
"Status": {},
"TaxTotal": {
"value": 0
},
"Totals": {
"FreightCost": {
"value": 0
},
"DiscountTotal": {
"value": 0
},
"LineTotalAmount": {
"value": 79.99
},
"custom": {}
},
"custom": {
"Document": {
"AttributeAMT": {
"value": "79.99",
"type": "CustomStringField"
},
"AttributeAUTHID": {
"value": "23456",
"type": "CustomStringField"
},
"AttributeCUR": {
"value": "USD",
"type": "CustomStringField"
},
"AttributeDT": {
"value": "6/2/2021 4:13:01 PM",
"type": "CustomStringField"
},
"AttributeEXPDATE": {
"value": "2025-05",
"type": "CustomStringField"
},
"AttributeRC": {
"value": "0",
"type": "CustomStringField"
},
"AttributeTOKEN": {
"value": "Gmg9niiBqh8B8FXH",
"type": "CustomStringField"
},
"AttributeTRANID": {
"value": "12345",
"type": "CustomStringField"
},
"AttributeCID": {
"value": "B",
"type": "CustomStringField"
},
"AttributeSTATUS": {
"value": "Pending",
"type": "CustomStringField"
}
}
}
}
</code></pre>
public async Task Upsert(BusinessModel.Order
order)
{
// Map BusinessModel to DTO
var request = _mapper.Map(order);
//Add Payment record
DataModel.SalesOrderPayment payment = new
DataModel.SalesOrderPayment();
payment.Description = new StringValue { Value =
string.Format("Payment for {0}", order.OrderNumber)};
payment.PaymentMethod = new StringValue { Value =
"CUSTOMPAYMC" };
payment.CardAccountNbr = new StringValue { Value =
string.Concat(order.PaymentDetails.CardID) };
payment.CashAccount = new StringValue { Value = "10600" };
payment.ProcessingCenterID = new StringValue { Value =
"CUSTOMPAY"};
payment.Hold = new BooleanValue { Value = false };
payment.PaymentAmount = new DecimalValue { Value =
order.Header.TotalAmount };
payment.AppliedToOrder = new DecimalValue { Value =
order.Header.TotalAmount };
payment.Custom = new Dictionary>();
payment.Status = new StringValue { Value = "Pre-Authorized"
};
DataModel.SalesOrderCreditCardTransactionDetail detail = new
DataModel.SalesOrderCreditCardTransactionDetail();
detail.AuthNbr = new StringValue { Value =
order.PaymentDetails.AuthorizationNumber };
detail.NeedValidation = new BooleanValue { Value = false };
detail.TranDate = new DateTimeValue { Value =
order.PaymentDetails.AuthorizationDateTime };
detail.TranNbr = new StringValue { Value =
order.PaymentDetails.TransactionID };
detail.TranType = new StringValue { Value = "Authorize Only"
};
detail.Custom = new Dictionary>();
payment.CreditCardTransactionInfo = new
List();
//payment.CreditCardTransactionInfo.Add(detail);
request.Payments = new List();
request.Payments.Add(payment);
// Invoke API
SalesOrder salesOrderResponse = await
api.PutEntityAsync(request, null, null, null, null));
// Map response DTO to BusinessModel
var response = _mapper.Map
(salesOrderResponse);
return Ok(response);
}
Related
I'm currently facing an issue with my datatable implemented in ReactJS. I'm retrieving data from elasticsearch and populating the datatable with it. The data retrieval process works fine without the filter applied, however, when I apply filters to the data, the datatable remains empty, even though the data _source has matching records.
The structure of the parameters I am sending is as follows:
{
pageIndex: 1,
pageSize: 10,
sort: { order: '', key: '' },
query: '',
filterData: {
analysis: [ '0', '1', '2', '3' ],
threat_level_id: [ '1', '2', '3', '4' ],
}
}
EndPoint:
POST /api/v1/events/public/list
Controller:
exports.getPublicEvents = async (req, res) => {
try {
client.ping()
const { pageIndex, pageSize, sort, query, filterData } = req.body
let esQuery = {
index: 'ns_*',
body: {
query: {
bool: {
must: [
{
match_all: {},
},
],
filter: [],
},
},
from: (pageIndex - 1) * pageSize,
size: pageSize,
},
}
if (query) {
esQuery.body.query.bool.must = [
{
match: {
'Event.info': {
query: query,
fuzziness: 'AUTO',
},
},
},
]
}
if (filterData.analysis.length > 0) {
esQuery.body.query.bool.filter.push({
terms: {
'Event.analysis': filterData.analysis,
},
})
}
if (filterData.threat_level_id.length > 0) {
esQuery.body.query.bool.filter.push({
terms: {
'Event.threat_level_id': filterData.threat_level_id,
},
})
}
let esResponse = await client.search(esQuery)
let data = esResponse.hits.hits.map((hit) => hit._source)
let total = esResponse.hits.total.value
res.status(200).json({
status: 'success',
data: data,
total: total,
})
} catch (error) {
res.status(500).json({
error: 'Error connecting to Elasticsearch',
errorMessage: error.message,
})
}
}
The controller below is without filters and it works just fine.
exports.getPublicEvents = async (req, res) => {
try {
client.ping()
const { pageIndex, pageSize, sort, query } = req.body
let esQuery = {
index: 'ns_*',
body: {
query: {
match_all: {},
},
from: (pageIndex - 1) * pageSize,
size: pageSize,
},
}
if (query) {
esQuery.body.query = {
match: {
'Event.info': {
query: query,
fuzziness: 'AUTO',
},
},
}
}
let esResponse = await client.search(esQuery)
let data = esResponse.hits.hits.map((hit) => hit._source)
let total = esResponse.hits.total.value
res.status(200).json({
status: 'success',
data: data,
total: total,
})
} catch (error) {
res.status(500).json({
error: 'Error connecting to Elasticsearch',
errorMessage: error.message,
})
}
}
ElasticSearech version: 7.17.8
Result of: console.log(JSON.stringify(esQuery))
{
"index": "INDEX_NAME",
"body": {
"query": {
"bool": {
"must": [{ "match_all": {} }],
"filter": [
{ "terms": { "Event.analysis": ["0", "1", "2"] } },
{ "terms": { "Event.threat_level_id": ["1", "2", "3", "4"] } }
]
}
},
"from": 0,
"size": 10
}
}
Data in elascticsearch schema
{
"#version": "1",
"#timestamp": "2023-02-01T14:43:09.997Z",
"Event": {
"info": ".......................",
"description": ".......................",
"analysis": 0,
"threat_level_id": "4",
"created_at": 1516566351,
"uuid": "5a64f74f0e543738c12bc973322",
"updated_at": 1675262417
}
}
Index Mapping
{
"index_patterns": ["INDEX_NAME"],
"template": "TEMPLATE_NAME",
"settings": {
"number_of_replicas": 0,
"index.mapping.nested_objects.limit": 10000000
},
"mappings": {
"dynamic": false,
"properties": {
"#timestamp": {
"type": "date"
},
"Event": {
"type": "nested",
"properties": {
"date_occured": {
"type": "date"
},
"threat_level_id": {
"type": "integer"
},
"description": {
"type": "text"
},
"is_shared": {
"type": "boolean"
},
"analysis": {
"type": "integer"
},
"uuid": {
"type": "text"
},
"created_at": {
"type": "date"
},
"info": {
"type": "text"
},
"shared_with": {
"type": "nested",
"properties": {
"_id": {
"type": "text"
}
}
},
"updated_at": {
"type": "date"
},
"author": {
"type": "text"
},
"Attributes": {
"type": "nested",
"properties": {
"data": {
"type": "text"
},
"type": {
"type": "text"
},
"uuid": {
"type": "text"
},
"comment": {
"type": "text"
},
"category": {
"type": "text"
},
"value": {
"type": "text"
},
"timestamp": {
"type": "date"
}
}
},
"organisation": {
"type": "nested",
"properties": {
"name": {
"type": "text"
},
"uuid": {
"type": "text"
}
}
},
"Tags": {
"type": "nested",
"properties": {
"color": {
"type": "text"
},
"name": {
"type": "text"
}
}
},
"TLP": {
"type": "nested",
"properties": {
"color": {
"type": "text"
},
"name": {
"type": "text"
}
}
}
}
}
}
}
}
Event is a nested field, so you need to use nested queries, like this:
{
"index": "INDEX_NAME",
"body": {
"query": {
"bool": {
"must": [{ "match_all": {} }],
"filter": [
{
"nested": {
"path": "Event",
"query": {"terms": { "Event.analysis": ["0", "1", "2"] }}
}
},
{
"nested": {
"path": "Event",
"query": {"terms": { "Event.threat_level_id": ["1", "2", "3", "4"] }}
}
}
]
}
},
"from": 0,
"size": 10
}
}
I am doing an integration with Acumatica.
In my SalesOrder request, I am creating a Sales Order with Bill-To Address and Ship-To Address.
After the request was made I have check in acumatica Sales Order that the Sales Order do not have the Bill-To and Ship-To Address as specified in my request.
It seems that it is using the Default Address that was set in the CustomerID
Here is a sample API which shows how to override the Ship-To address. Pay attention to the ShipTo entity declared
{
"OrderNbr": {
"value": "37631"
},
"OrderType": {
"value": "SO"
},
"Date": {
"value": "12/18/20 2:21:10 PM"
},
"note": " ",
"CustomerID": {
"value": "ABC123"
},
"ExternalRef": {
"value": "37631"
},
"Description": {
"value": "Self Import"
},
"CustomerOrder": {
"value": " "
},
"Processed": {
"value": false
},
"ShippingSettings": {
"Priority": {
"value": 2
},
"ShipVia": {
"value": "2ND_DAY"
}
},
"ShipToContactOverride": {
"value": true
},
"ShipToContact": {
"BusinessName": {
"value": "Bob Jones"
},
"Attention": {
"value": ""
},
"Phone1": {
"value": ""
},
"Email": {
"value": ""
}
},
"ShipToAddressOverride": {
"value": true
},
"ShipToAddress": {
"AddressLine1": {
"value": "123 Main Street"
},
"AddressLine2": {
"value": ""
},
"AddressLine3": {
"value": ""
},
"City": {
"value": "Ft. Smith"
},
"State": {
"value": "AR"
},
"PostalCode": {
"value": "72913"
}
},
"Details": [
{
"InventoryID": {
"value": "7239-1"
},
"OrderQty": {
"value": 2
},
"UnitPrice": {
"value": 35.07
}
},
{
"InventoryID": {
"value": "7543"
},
"OrderQty": {
"value": 2
},
"UnitPrice": {
"value": 436.98
}
},
{
"InventoryID": {
"value": "6243-2"
},
"OrderQty": {
"value": 8
},
"UnitPrice": {
"value": 5.43
}
}
]
}
I have an array of json object like this:
[
{
"entity": "clientModal",
"value": "MacBook"
},
{
"entity": "siteName",
"value": "abde"
},
{
"entity": "clientModal",
"value": "MacBook"
},
{
"entity": "siteName",
"value": "abcd"
},
{
"entity": "clientName",
"value": "ghe-1202m"
},
{
"entity": "timePeriod",
"value": "week"
},
{
"entity": "clientName",
"value": "ghe-1202m"
},
{
"entity": "timePeriod",
"value": "week"
},
{
"entity": "clientName",
"value": "ghe-1202m"
},
{
"entity": "clientName",
"value": "ppphone"
},
{
"entity": "clientName",
"value": "pppiphone"
}
]
I want that key 'entity' should be replaced by its value everywhere and the key'value' must be inside it.
Like this:
[
{
"clientName":
{
"value":"ppiphone"
}
}
]
I tried evreything but still not find anything.
You need to map the array and create a new object wherein the entity value will serve as the name of the key.
const arrays = [
{
"entity": "clientModal",
"value": "MacBook"
},
{
"entity": "siteName",
"value": "abde"
},
{
"entity": "clientModal",
"value": "MacBook"
},
{
"entity": "siteName",
"value": "abcd"
},
{
"entity": "clientName",
"value": "ghe-1202m"
},
{
"entity": "timePeriod",
"value": "week"
},
{
"entity": "clientName",
"value": "ghe-1202m"
},
{
"entity": "timePeriod",
"value": "week"
},
{
"entity": "clientName",
"value": "ghe-1202m"
},
{
"entity": "clientName",
"value": "ppphone"
},
{
"entity": "clientName",
"value": "pppiphone"
}
];
const mappedArray = arrays.map(arr => ({
[arr.entity]: {
value: arr.value
}
}));
console.log(mappedArray);
Let's try something without create new array for output. Just modify existing:
for (let i = 0; i < arrays.length; i++) {
arrays[i] = {
[arrays[i].entity]: {
value: arrays[i].value
}
}
}
console.log(arrays)
Followed a much basic approach of looping.
var a = [
{
"entity": "clientModal",
"value": "MacBook"
},
{
"entity": "siteName",
"value": "abde"
},
{
"entity": "clientModal",
"value": "MacBook"
}
];
var finalArray = []
for(let i = 0; i < a.length; i++) {
let s =`{ "${a[i].entity}": { "value": "${a[i].value}" } }`;
finalArray.push(JSON.parse(s));
}
console.log(JSON.stringify(finalArray));
Output:
[{"clientModal":{"value":"MacBook"}},{"siteName":{"value":"abde"}},{"clientModal":{"value":"MacBook"}}]
Using acumatica web services (json REST api), how can I set the TaxZone when I create an Invoice. Here's a sample json put request:
{
"Date": { "value": "12/23/2019" },
"DueDate": { "value": "12/23/2019" },
"Customer": { "value": "12345" },
"Type": { "value": "Invoice" },
"LinkBranch": { "value": "MYBRANCH" },
"FinancialDetails": {
"TaxZone": { "value": "1" }
}
}
I have tried that, tried TaxZoneId, tried posting without using FinancialDetails object... nothing seems to work.
The easiest way to get the correct structure of the JSON is to send get request with "expand" parameter like below:
http://localhost/ACU19200/entity/Default/18.200.001/SalesInvoice/Invoice|AR007541?$expand=FinancialDetails
This will return you the Invoice record with Financial Details, like below:
{
"id": "7bd77116-dcf1-e911-b312-fc017c8c8936",
"rowNumber": 1,
"note": "",
"Amount": {
"value": 2385.0000
},
"Balance": {
"value": 1910.0000
},
"CashDiscount": {
"value": 0.0000
},
"CreditHold": {
"value": false
},
"Currency": {
"value": "USD"
},
"CustomerID": {
"value": "ABARTENDE"
},
"CustomerOrder": {},
"Date": {
"value": "2019-10-18T00:00:00-07:00"
},
"Description": {},
"DueDate": {
"value": "2019-11-17T00:00:00-08:00"
},
"FinancialDetails": {
"id": "1b004ff5-496f-463e-8b37-f6c74a044482",
"rowNumber": 1,
"note": null,
"BatchNbr": {
"value": "AR006749"
},
"Branch": {
"value": "PRODWHOLE"
},
"CustomerTaxZone": {},
"custom": {},
"files": []
},
"Hold": {
"value": false
},
"Project": {
"value": "X"
},
"ReferenceNbr": {
"value": "AR007541"
},
"Status": {
"value": "Open"
},
"Type": {
"value": "Invoice"
},
"VATExemptTotal": {
"value": 0.0000
},
"VATTaxableTotal": {
"value": 0.0000
},
"custom": {},
"files": []
}
Now after we have the structure we need to remove the redundant fields from the request and send the PUT request with the JSON like below (of course in your case you need to also provide invoice details and other information):
{
"CreditHold": {
"value": false
},
"Currency": {
"value": "USD"
},
"CustomerID": {
"value": "ABARTENDE"
},
"Description": {
"value" : "Test Invoice"
},
"Hold": {
"value": false
},
"Status": {
"value": "Open"
},
"Type": {
"value": "Invoice"
},
"FinancialDetails": {
"CustomerTaxZone": {
"value": "AVALARA"
}
}
}
You will need to extend the default endpoint if you need to work with AR Invoice (Default/18.200.001/Invoice) because it doesn't contain CustomerTaxZone by default.
You can do it as shown below and then just send CustomerTaxZone as "TaxZone" on the top level.
Including them in the Attribute collection of a Stock Item doesn't seem to work -- even if I make sure the attribute ids already exist in the db. When I do the PUT request, the rest of the data in the record is inserted, but not the attributes. The response even returns an empty attribute array instead of what I sent to it.
Do I need to extend the API for this to work? If so, does anyone have any examples? I haven't been able to find any yet.
The request is:
http://localhost/acum172100034/entity/Default/17.200.001/StockItem
The body is:
{
"InventoryID": {
"value": "RGTONYIT166"
},
"Attributes": [
{
"AttributeID": {
"value": "Item Attribute"
},
"Value": {
"value": "2"
}
}
]
}
The PUT response is:
{
"id": "665e403c-d310-4bb4-9759-e2487dd5abc7",
"rowNumber": 1,
"note": null,
"ABCCode": {},
"Attributes": [],
"AutoIncrementalValue": {},
"AverageCost": {
"value": 0
},
"BaseUOM": {
"value": "EA"
},
"COGSAccount": {
"value": "50000"
},
"COGSSubaccount": {
"value": "CON000"
},
"Content": {},
"CurrentStdCost": {
"value": 0
},
"DefaultIssueLocationID": {
"value": "R1S1"
},
"DefaultPrice": {
"value": 0
},
"DefaultReceiptLocationID": {
"value": "RECEIVING"
},
"DefaultWarehouseID": {
"value": "WHOLESALE"
},
"DeferralAccount": {},
"DeferralSubaccount": {},
"Description": {
"value": "tonyitem166 - blah blah 2"
},
"DimensionVolume": {
"value": 3
},
"DimensionWeight": {
"value": 2
},
"DiscountAccount": {},
"DiscountSubaccount": {},
"ImageUrl": {},
"InventoryAccount": {
"value": "12100"
},
"InventoryID": {
"value": "RGTONYIT166"
},
"InventorySubaccount": {
"value": "CON000"
},
"IsAKit": {
"value": false
},
"ItemClass": {
"value": "CONSUMER 200FITNESS"
},
"ItemStatus": {
"value": "Active"
},
"ItemType": {
"value": "Finished Good"
},
"LandedCostVarianceAccount": {
"value": "52400"
},
"LandedCostVarianceSubaccount": {
"value": "CON000"
},
"LastCost": {
"value": 0
},
"LastModified": {
"value": "2018-10-02T17:13:38.707-04:00"
},
"LastStdCost": {
"value": 0
},
"LotSerialClass": {
"value": "NOTTRACKED"
},
"Markup": {
"value": 0
},
"MaxCost": {
"value": 0
},
"MinCost": {
"value": 0
},
"MinMarkup": {
"value": 0
},
"MSRP": {
"value": 0
},
"PackagingOption": {
"value": "Manual"
},
"PackSeparately": {
"value": false
},
"PendingStdCost": {
"value": 0
},
"POAccrualAccount": {
"value": "20100"
},
"POAccrualSubaccount": {
"value": "CON000"
},
"PostingClass": {
"value": "CON"
},
"PriceClass": {},
"PriceManager": {},
"PriceWorkgroup": {},
"ProductManager": {},
"ProductWorkgroup": {},
"PurchasePriceVarianceAccount": {
"value": "52300"
},
"PurchasePriceVarianceSubaccount": {
"value": "CON000"
},
"PurchaseUOM": {
"value": "EA"
},
"ReasonCodeSubaccount": {
"value": "CON000"
},
"SalesAccount": {
"value": "40000"
},
"SalesSubaccount": {
"value": "CON000"
},
"SalesUOM": {
"value": "EA"
},
"StandardCostRevaluationAccount": {
"value": "52110"
},
"StandardCostRevaluationSubaccount": {
"value": "CON000"
},
"StandardCostVarianceAccount": {
"value": "52100"
},
"StandardCostVarianceSubaccount": {
"value": "CON000"
},
"SubjectToCommission": {
"value": false
},
"TaxCategory": {
"value": "TAXABLE"
},
"ValuationMethod": {
"value": "Average"
},
"VolumeUOM": {},
"WeightUOM": {},
"custom": {},
"files": []
}
If the Attributes are already present on the Stock Item screen, then you can use the Default endpoint and you only need to make a PUT call specifying the Inventory ID and the Attribute ID like so:
PUT : localhost/demo172u10/entity/Default/17.200.001/StockItem
{
"InventoryID": {"value": "AACOMPUT01"},
"Attributes":
[
{
"AttributeID": {"value": "Color"},
"Value": {"value": "Black"}
},
{
"AttributeID": {"value": "Configurable Attributes"},
"Value": {"value": "Test"}
}
]
}
This would update the "Color" and "Configurable Attributes" Attributes of the AACOMPUT01 Stock Item with the value specified.
If the Attribute is not on the Stock Item screen then you would need to use the API to target the Item Class screen to add the Attributes that you want there. As if you go to the Stock Item screen you might notice that you cannot add new attributes directly on that screen and that they are actually coming from the Item Class of the Item itself.
This test was done using the Sales Demo Data with Acumatica Version 17.210.0034
This is a guess, but I think you need to add your attributes to your stock item class. Go to IN201000
This ended up being an issue with my own code that was apparently hiding the attributes from the view so that they wouldn’t update. Once I resolved that, now it's working by just include them in the Attributes collection.