How to provide structure parameter as import in Bapi call with Cloud SDK v3 - sap-cloud-sdk

I am using BAPI BAPI_PR_CREATE on S4HANA on-premise system to create purchase requisition with Cloud SDK v3.
The parameters to create purchase requisition are as below based on BAPI documentation.
Parameter: PRHEADER
PR_TYPE = NB
Parameter: PRHEADERX
PR_TYPE = X
Parameter: PRITEM
PREQ_ITEM = 00010
PUR_GROUP = 001
MATERIAL = 100-100
PLANT = 1000
QUANTITY = 5.000
Parameter: PRITEMX
PREQ_ITEM = 00010
PREQ_ITEMX = X
PUR_GROUP = X
MATERIAL = X
PLANT = X
QUANTITY = X
The following are my java code. The type of export parameter PRHEADER and PRHEADERX are structure. Could you provide how to construct the object PRHEADER and PRHEADERX?
final BapiRequest bapiCreate = new BapiRequest("BAPI_PR_CREATE")
.withExporting("PRHEADER", "BAPIMEREQHEADER", ????)
.withExporting("PRHEADERX", "BAPIMEREQHEADERX", ????)
.withImporting("NUMBER", "BAPIMEREQHEADER-PREQ_NO")
.withTableAsReturn("BAPIRET2");
// PR Item table
bapiCreate.withTable("PRITEM", "BAPIMEREQITEMIMP")
.row()
// PR Item
.field("PREQ_ITEM", "BNFPO", "00010")
// Purchase Group
.field("PUR_GROUP", "EKGRP", "***")
// Material
.field("MATERIAL", "MATNR18", "***")
// Plant
.field("PLANT", "EWERK", "***")
// Requested quantity
.field("QUANTITY", "BAMNG", "***")
.end();
// PR ItemX table
bapiCreate.withTable("PRITEMX", "BAPIMEREQITEMX")
.row()
// PR Item
.field("PREQ_ITEM", "BNFPO", "00010")
// PR ItemX
.field("PREQ_ITEMX", "BAPIUPDATE", "X")
// Purchase Group
.field("PUR_GROUP", "BAPIUPDATE", "X")
// Material
.field("MATERIAL", "BAPIUPDATE", "X")
// Plant
.field("PLANT", "BAPIUPDATE", "X")
// Requested quantity
.field("QUANTITY", "BAPIUPDATE", "X")
.end();
Update
I need to use method "withExportingFields" to construct data with type "Structure".
final BapiRequest bapiCreate = new BapiRequest("BAPI_PR_CREATE")
.withExportingFields("PRHEADER", "BAPIMEREQHEADER")
.field("PR_TYPE", "BANFN", "NB")
.end();
bapiCreate.withExportingFields("PRHEADERX", "BAPIMEREQHEADERX")
.field("PR_TYPE", "BAPIUPDATE", "X")
.end();

I think you can treat "Structures" similar to "Tables", e.g.
bapiCreate.withExportingFields("PRHEADER", "BAPIMEREQHEADER")
.row()
.field("columnName1", "dataType1", "value1")
.field("columnName2", "dataType2", "value2")
.end();
(Updated withExportingTable to withExportingFields, due to feedback)

Related

Get the names of a dynamic product group with a subscriber in Shopware 6.1

how can I get the names of the dynamic product groups of a product?
Especially the names of that groups. The names are in the table 'product_stream_translation'.
I have a subscriber and have added this Criteria. When I am doing it like this:
$criteria->addFilter(new EqualsFilter('id', $id));
$criteria->addAssociation('streams');
$dynamicProductGroups = $this->productRepository->search($criteria, $context)->getEntities();
I just got back an empty streamEntity.
#streams: Shopware\Core\Content\ProductStream\ProductStreamCollection {#11805 ▼
#elements: []
#extensions: []
}
When I am doing it like this:
$criteria->addFilter(new EqualsFilter('productId', $id));
$dynamicProductGroups = $this->productStreamMappingRepository->searchIds($criteria, $context);
I just got back the Id I put in:
product_stream_mapping
I wonder how I will get the name of the dynamic product group.
With a query I can get all the assign 'product_stream_id's from the table 'product_stream_mapping' like this:
SELECT * FROM product_stream_mapping WHERE product_id =0x000000000000000000123b313030524b
And then get the associated name of the dynamic product group. With is like this:
SELECT psm.product_id, psm.product_stream_id, p.product_number, pst.name
FROM product_stream_mapping psm
JOIN product_stream_translation pst ON pst.product_stream_id = psm.product_stream_id
JOIN product p ON p.id = psm.product_id
WHERE psm.product_id = 0x000000000000000000123b313030524b
How can I get it in the Subscriber?
Do I have to use criteria or do I have to user a repository?
This line is wrong:
$dynamicProductGroups = $this->productRepository->search($criteria, $context)->getEntities();
It won't return dynamic product groups but a product collection. To get a product stream collection (dynamic product groups) replace it with:
/** #var ProductEntity $product */
$product = $this->productRepository->search($criteria, $context)->first();
$dynamicProductGroups = $product->getStreams();
Then you can read the names of the streams with:
$names = array_values(
$dynamicProductGroups->map(fn (ProductStreamEntity $productStream) => $productStream->getName())
);

Problems with the BQL "IN<>" statement

The requirement I have is to get a list of all discount codes defined in an instance and which ones a particular customer is currently assigned to, in the case given CustomerID=28. I further have to include only discount codes that naturally will be applicable to customers. There are only 3 of these; "Customer", "Customer and Item", "Customer and Item price Class". These are ARDiscount.ApplicableTo containing "CU", "CP","CI"
Select a.CompanyID, a.DiscountID, a.DiscountSequenceID, b.ApplicableTo, c.CustomerID
From DiscountSequence a
Join ARDiscount b On a.CompanyID = b.CompanyID and a.DiscountID = b.DiscountID
Left Outer Join DiscountCustomer c On a.CompanyID = c.CompanyID
And a.DiscountID = c.DiscountID
And a.DiscountSequenceID = c.DiscountSequenceID
And (IsNull(c.CustomerID,0) = 0 OR c.CustomerID = 72)
Where a.CompanyID = 2
And b.ApplicableTo In ('CU','CP','CI')
Order By a.DiscountID, a.DiscountSequenceID
I created data view delegate to return the 4 columns I need to display and in the view I created
to read the data like the SQL query above I used the BQL "IN<>" statement like this. The method was taken directlty from a blog post found here :
https://asiablog.acumatica.com/2017/11/sql-in-operator-in-bql.html
Object[] applicableTovalues = new String[] { "CP","CI","CU" }; // Customer and Price Class // Customer and Item// Customer
var Results = PXSelectJoin<DiscountSequence
, InnerJoin<ARDiscount, On<DiscountSequence.discountID, Equal<ARDiscount.discountID>>
, LeftJoin<DiscountCustomer, On<DiscountSequence.discountID, Equal<DiscountCustomer.discountID>,
And<DiscountSequence.discountSequenceID, Equal<DiscountCustomer.discountSequenceID>,
And<Where<DiscountCustomer.customerID, Equal<Current<Customer.bAccountID>>,
Or<DiscountCustomer.customerID, IsNull>>>>>>>
, Where<DiscountSequence.discountID, IsNotNull
, And<ARDiscount.applicableTo, In<Required<ARDiscount.applicableTo>>>>
, OrderBy<Asc<DiscountSequence.discountID, Asc<DiscountSequence.discountSequenceID>>>
>.Select(Base, applicableTovalues);
The problem is that the resulting SQL server select statement caught with TRACE only includes the first of the three IN values (''CU'') leaving (CI and CU) out.
I was expecting all three values in the IN statement like this : AND [ARDiscount].[ApplicableTo] IN ( ''CP'', ''CI'', ''CU'')
exec sp_executesql N'SELECT [DiscountSequence].[DiscountID], [DiscountSequence].[DiscountSequenceID], [DiscountSequence].[LineCntr],
<snip>
[DiscountCustomer].[CreatedDateTime], [DiscountCustomer].[LastModifiedByID], [DiscountCustomer].[LastModifiedByScreenID], [DiscountCustomer].[LastModifiedDateTime]
FROM [DiscountSequence] [DiscountSequence] INNER JOIN [ARDiscount] [ARDiscount] ON ( [ARDiscount].[CompanyID] = 2) AND [DiscountSequence].[DiscountID] = [ARDiscount].[DiscountID]
LEFT JOIN [DiscountCustomer] [DiscountCustomer] ON ( [DiscountCustomer].[CompanyID] = 2) AND [DiscountSequence].[DiscountID] = [DiscountCustomer].[DiscountID]
AND [DiscountSequence].[DiscountSequenceID] = [DiscountCustomer].[DiscountSequenceID] AND ( [DiscountCustomer].[CustomerID] = #P0 OR [DiscountCustomer].[CustomerID] IS NULL )
WHERE ( [DiscountSequence].[CompanyID] = 2)
AND ( [DiscountSequence].[DiscountID] IS NOT NULL
AND [ARDiscount].[ApplicableTo] IN ( ''CU''))
ORDER BY [DiscountSequence].[DiscountID], [DiscountSequence].[DiscountSequenceID]
OPTION(OPTIMIZE FOR UNKNOWN) /* AR.30.30.00 */',N'#P0 int',#P0=39
The issue is passing the array into the 'params' parameter. It thinks that you are passing a list of parameters into the bql query instead of a single array as a parameter.
If you cast it as follows it should work:
.Select(Base, (object)applicableTovalues);

How to use list parameters in Fulfillment

I have a composite entity named #flavorQuantity.
This entity collects the "flavors" present in the order and their "quantities", in phrases like "I want 2 cocoa and 1 pumpkin", like this:
want #sys.number:quantity #flavor:flavor and #sys.number:quantity #flavor:flavor
Dialogflow identifies these parameters ($quantity and $flavor) separately, as in the image:
PT-BR = saborQuantidade = #flavorQuantity || Cacau = Cocoa || Punpkin = Abóbora
How can I use each of these parameters in Fulfillmment to set up a function that provides the total value of each item, to add up the total value of the order. Using the function below it does not recognize the name of the values ​​contained within the parameter #flavorQuantity.
**
function order (agent){
const quantity = agent.parameters.quantity;
const flavor = agent.parameters.flavor;
var total;
if (flavor == 'Cacau & Castanhas'){
total = 3*quantity;
**
have you tried agent.queryResult.parameters.quantity?

How can bypass the credit limit while creating invoice or saleorder in Netsuite using SuiteTalk Webservice?

I am using Netsuite SuiteTalk web service since 3-4 months I felt comfortable to use it. now, i have issues i want to create saleorder/invoice in netsuite using SuiteTalk but i am unable to do that because everytime i am getting error of credit limit i.e customer invoice amount is more than their credit limit. it's O.K, but as long as i am sending payments too with the same webservice request.
I would appreciate if someone or Netsuite people can help me to bypass credit limit while creating invoice.
please have a look suitetalk c# code.
Invoice inv = new Invoice();
inv.entity = new RecordRef() { internalId = 25, type = RecordType.customer, typeSpecified = true };
inv.tranDate = new DateTime(2018,9,18);
inv.memo = "Test Memo";
inv.department = new RecordRef() { internalId = 10, type = RecordType.department, typeSpecified = true };
inv.location = new RecordRef() { internalId = 16, type = RecordType.location, typeSpecified = true };
InvoiceItemList itemList = new InvoiceItemList();
InvoiceItem[] items = new InvoiceItem[1];
// invoice items
InvoiceItem item = new InvoiceItem();
item.item = new RecordRef() { internalId = 12510 };
item.rate = 2.65;
item.amount = 265.00;
item.quantity = 100;
items[0] = item;
itemList.item = items;
inv.itemList = itemList;
inv.amountPaid = 180;
inv.amountPaidSpecified = true;
inv.onCreditHold = "true";
WriteResponse writeRes = ns.Service.add(inv);
Try below solution
Go to -> Setup -> Accounting -> Accounting Preferences
In General tab account Receivable section
See that CUSTOMER CREDIT LIMIT HANDLING field. choose appropriate value based on your situation.
Ignore – Select this method to allow sales orders and invoices to be entered without a warning for a customer that is at or above their credit limit.
Warn Only – Select this method to generate a warning when a sales order or invoice is being entered that puts the customer at or above their credit limit. You can choose to enter or cancel the transaction once the warning has appeared.
Enforce Holds – Select this method to block the entry of a sales order or invoice that puts the customer at or above their credit limit. This method also blocks the addition of items to existing orders for customers at or above their credit limit.
I have found the best solution, in order to avoid credit limit while creating invoice we can create Payment as PaymentItem and then we need to add in invoice.

How to load items with SuiteScript Purchase Orders?

Friends'm working with NetSuite and SuiteScript. I can save a purchase order running the script and also charge Purchase Orders created, but when I bring returns data item value as a null value, and I need to get the id of the item.
The result gives me the log NetSuite is:
Purchase Order ID: 3706 Vendor ID: 144 Item ID: null Trandate: 06/08/2015 Form: Standard Purchase Order Currency: Peso CL
this happens all Purchase Orders and obviously if you have an item attached.
function to load javascript to use Purchase Order is as follows:
function loadPurchaseOrder(){
nlapiLogExecution('DEBUG','loadPurchaseOrder', 'Entra a funcion loadPurchaseOrder');
//se aplican filtros para la busqueda del objeto
var filters= new Array();
filters[0] = new nlobjSearchFilter('purchaseorder',null,'isnotempty');
filters[1] = new nlobjSearchFilter('mainline', null, 'is', 'T');
//seleccion de los campos que se quieren extraer
var columns = new Array();
columns[0] = new nlobjSearchColumn('item');
columns[1] = new nlobjSearchColumn('entity');
columns[2] = new nlobjSearchColumn('trandate');
columns[3] = new nlobjSearchColumn('customform');
columns[4] = new nlobjSearchColumn('currency');
columns[5] = new nlobjSearchColumn('internalid');
var results = nlapiSearchRecord('purchaseorder',null,filters,columns);
var out = "";
if(results != null ){
for(var i=0; i< results.length; i++){
var purchaseOrder = results[i];
var idItem = purchaseOrder.getValue('item');
var idVendor = purchaseOrder.getValue('entity');
var trandate = purchaseOrder.getValue('trandate');
var form = purchaseOrder.getText('customform');
var currency = purchaseOrder.getText('currency');
var idPurchaseOrder = purchaseOrder.getText('internalid');
out = " ID Purchase Order: " + idPurchaseOrder + " ID Vendor: " + idVendor + " ID Item: " + idItem
+ " Trandate: " + trandate + " Form: " + form + " Currency: " + currency;
nlapiLogExecution('DEBUG','purchaseOrderCargada', out);
}
}
return out;
}
If someone could please help me. Greetings!
pd:
I've also tried:
var idItem = nlapiGetLineItemField ('item', 'item');
and it does not work = /
This is maybe a longer answer than you're expecting, but here we go.
NetSuite divides Transaction records (Purchase Order is a type of Transaction) into Body and Line Item fields. When you do a Transaction search that includes mainline = 'T', you are telling NetSuite to only retrieve Body field data. The item field, however, is a Line Item field, so NetSuite will not return any data for it. That's why idItem is null.
Understanding the behaviour of the mainline filter is crucial to Transaction searches. Basically, it goes like this:
mainline = 'T' will only return body field data, so it will return exactly one search result per Transaction
mainline = 'F' will only return line item data, so it will return one search result for every line item on matching Transactions
mainline not specified will return both body field and line data, so it will return one result for each transaction itself plus one result for each line on each transaction.
Here's a concrete example. Let's say that there is only one Purchase Order in the system that matches all of your other search filters (besides mainline), and that Purchase Order has three items on it. This is how the search results will change based on the mainline filter:
If mainline = 'T' then you will get exactly one result for the Purchase Order, and you will only get data for Search Columns that are Body fields.
If mainline = 'F' then you will get exactly three results, one for each line item, and all of your Search Columns will contain data whether they are Body or Line fields
If mainline is not specified then you will get exactly four results, one of them will only contain data for Body fields, and the other three will contain both Line and Body data
It's difficult to advise on exactly how you should change your search as I do not know what you plan to do with these search results.

Resources