How to insert Adjustment record with Contract API - acumatica

I'm trying to insert an adjustment record via the SOAP API using the following code.
Dim NewAdjustment As Adjustment = New Adjustment With {
.ExternalRef = New StringValue With {.Value = "TEST1234"},
.Description = New StringValue With {.Value = "1234TEST"},
.[Date] = New DateTimeValue With {.Value = "12/20/2018"},
.Details = {New AdjustmentDetail With {
.BranchID = New StringValue With {.Value = "PRODWHOLE"},
.InventoryID = New StringValue With {.Value = "18r.5"},
.WarehouseID = New StringValue With {.Value = "RETAIL"},
.Qty = New DecimalValue With {.Value = 100}
}}
}
Dim InsertAdjustment As Adjustment = CType(soapClient.Put(NewAdjustment), Adjustment)
I get an error px.data.pcexception: Error: 'Branch' cannot be empty. Error: 'Post Period' cannot be empty. Error Inserting 'Receipt' record raised at least one error.
I'm guessing I need to fill those values but I'm not sure how to do that. I see them in the table but not the API interface. I'm new to Acumatica, so I'm guessing this is just something I'm missing.
Thanks in advance.

I have never seen the usage of the Date property as [Date], but that does not mean it will not work. The Posting period is defaulted based on the value of the date property. Make sure that the December 2018 posting period is open on the company that you are logged into with the API. I have seen this error from time to time when the accounting department does not open the period in a timely fashion.
The BranchID is defaulted based on the login parameters of the soapClient. One thing to be aware of is that your API login user needs to have permissions to the BranchID being used, or you will definitely get an error about the Branch being invalid.
Depending on the Inventory costing methodology used by your company, Inventory Adjustments might require that they be processed against an inventory Receipt. This can be tricky to figure out what to do, especially if you have never received anything for this Item in a new implementation, and you want to increase inventory levels. For positive Adjustments in your business case, you might want to consider creating Inventory Receipts instead of Adjustments. The entity is very similar to the Adjustments. For negative Adjustments you might want to consider using Inventory Issues which is again, quite similar.
If you decide to use adjustments, you will have to search the Inventory Receipts for an appopriate Receipt number to use when populating the transaction details. One for each line you insert.

Related

How to charge existing customers for a products?

If you know Audible, that's how my service works. You can have subscriptions which you get credits for but you can also just buy single items right away (if you want).
Subscriptions work for me but what I can't get my head around is how I can charge an existing customer, using his default payment method, on a single item. Let's stick to Audible.
A user wants to buy a single audio-track.
I though I can:
Create a Product for this track (setting a name and an image-url)
Create or re-use a Price and set the charge-amount as stated in my database
Somehow create an Invoice or Charge for this Price/Product and move one
However, I just don't quite get how to do that.
Looking at the docs of Invoice, it appears to me that I am not able to add a single product or price and let Stripe automatically charge the customer.
I thought it would look something like this:
public void buyProduct(String productId, Customer customer) {
InvoiceCreateParams.builder()
.setCustomer(customer.getId())
.setDefaultPaymentMethod(customer.getPaymentMethod())
.setAutoAdvance(true)
.setCollectionMethod(CollectionMethod.CHARGE_AUTOMATICALLY)
// Add product/price here ?
.build();
// ...
}
So, what is the simplest way to charge a customer for a product?
Update
I noticed that an InvoiceItem can take a Invoice ID.
Is the following correct (in principal)?
Setting autoAdvance to true and CHARGE_AUTOMATICALLY as collection-method, will the user charged correctly as I intend to using the code below?
public void createInvoice() throws StripeException {
String customerId = null;
String paymentMethodId = null;
String priceId = null;
boolean chargeAutomatically = true;
InvoiceCreateParams invoiceCreateParams = InvoiceCreateParams.builder()
.setCustomer(customerId)
.setDefaultPaymentMethod(paymentMethodId)
.setAutoAdvance(chargeAutomatically)
.setCollectionMethod(CollectionMethod.CHARGE_AUTOMATICALLY)
.build();
Invoice invoice = Invoice.create(invoiceCreateParams);
InvoiceItemCreateParams invoiceItemCreateParams = InvoiceItemCreateParams.builder()
.setCustomer(customerId)
.setPrice(priceId)
.setInvoice(invoice.getId())
.build();
InvoiceItem invoiceItem = InvoiceItem.create(invoiceItemCreateParams);
}
It feels weird to create an invoice at first, and set everything up for charging a customer immediatelly, and only after having done so, set the actual item that the user wants to buy.
You should take a look at this: https://stripe.com/docs/billing/invoices/sending#one-off
First, you'll want to create an Invoice Item using the Price and Customer ID (no need to create the invoice first). You can create as many Invoice Items as you want, depending on how many things you want to charge your customer for. Then you can create an Invoice which will automatically pick up all the pending Invoice Items for a given Customer.

What is the proper way to update values of DAC's retrieved via PXResultset?

We have a business requirement to set the SO return COST to the original cost issued without invoicing if possible. We determined that Sales Orders are necessary to track issuing materials to our client, and we are cost driven rather than price driven. We use FIFO costing, but SO return orders do not seem to return at the original COST unless invoiced (which we also don't do in a traditional manner).
I found that setting the unit/ext cost on the SO Shipment Line directly in the database before Confirm Shipment and Update IN appears to provide the results desired. Applying a custom menu option to streamline and strongly control the return, I cloned nearby code as a base. The section between the === is where I set the unit/ext cost. The PXTrace shows the expected value, but it is coming out as $0 on the shipment record. I thought I might need "docgraph.Update(sOShipmentLine)" to save it, but that's not accessible in this scope.
using (var ts = new PXTransactionScope())
{
PXTimeStampScope.SetRecordComesFirst(typeof(SOOrder), true);
//Reminder - SOShipmentEntry docgraph = PXGraph.CreateInstance<SOShipmentEntry>();
docgraph.CreateShipment(order, SiteID, filter.ShipDate, adapter.MassProcess, SOOperation.Receipt, created, adapter.QuickProcessFlow);
PXTrace.WriteError("Setting Cost");
//Set Cost on Shipment to Cost On SO Line
PXResultset<SOShipment> results =
PXSelectJoin<SOShipment,
InnerJoin <SOShipLine, On<SOShipLine.shipmentNbr, Equal<SOShipment.shipmentNbr>>,
InnerJoin <SOLine, On<SOLine.orderType, Equal<SOShipLine.origOrderType>,
And<SOLine.orderNbr, Equal<SOShipLine.origOrderNbr>, And<SOLine.lineNbr, Equal<SOShipLine.origLineNbr>>>>
>>,
Where<SOShipment.shipmentNbr, Equal<Required<SOShipment.shipmentNbr>>>>
.Select(docgraph, docgraph.Document.Current.ShipmentNbr);
PXTrace.WriteError("Shipment {0} - Records {1}", docgraph.Document.Current.ShipmentNbr, results.Count);
foreach (PXResult<SOShipment, SOShipLine, SOLine> record in results)
{
SOShipment shipment = (SOShipment)record;
SOShipLine shipmentLine = (SOShipLine)record;
SOLine sOLine = (SOLine)record;
==============================================
shipmentLine.UnitCost = GetReturnUnitCost(sOLine.OrigOrderType, sOLine.OrigOrderNbr, sOLine.OrigLineNbr, sOLine.CuryInfoID);
shipmentLine.ExtCost = shipmentLine.Qty * shipmentLine.UnitCost;
PXTrace.WriteError(string.Format("{0} {1}-{2} = {3} / {4}", shipmentLine.LineType, shipmentLine.ShipmentNbr, shipmentLine.LineNbr, shipmentLine.Qty, shipmentLine.UnitCost));
==============================================
}
PXAutomation.CompleteSimple(docgraph.Document.View);
var items = new List<object> { order };
PXAutomation.RemovePersisted(docgraph, typeof(SOOrder), items);
PXAutomation.RemoveProcessing(docgraph, typeof(SOOrder), items);
ts.Complete();
}
Still on the learning curve so I'm expecting the solution is likely simple and obvious to someone more experienced.
There's three phase to it:
Changing the value
Updating the cache
Persisting the cache
I think you are changing the value but not persisting it. The reason why it works after invoking Confirm Shipment or Update IN action is probably that these actions will persist all changes by calling the graph Save action.
To change a field value in a data view you would do:
DACRecord.Field = value;
DataView.Update(DACRecord);
The particularity of your example is that the request is not bound to a data view.
When you have a loose BQL request you can do the same operation with a cache object. In your example the Caches context is available from docGraph:
DACRecord.Field = value;
graph.Caches[typeof(DACType)].Update(DACRecord);
graph.Caches[typeof(DACType)].Persist(DACRecord, PXDBOperation.Update);
Update and Persist are often omitted because in many scenarios they will be called later on by other framework mechanism. For example if you were to do only Update on a UI field, the record won't be persisted until the user clicks on the save button.
Updating value on UI is a bit different than updating in cache.
The recommended approach for UI fields is to use SetValue:
cache.SetValue<DAC.DacField>(DACRecord, fieldValue);
Or use SetValueExt when you want to trigger the framework events like FieldUpdated when changing the field value:
cache.SetValueExt<DAC.DacField>(DACRecord, fieldValue);
You'll still have to update and persist the changes in cache for these too if you want the changes to stick without requiring the user to manually save the document.

Acumatica Web API Apply Discounts

I am trying to get a way to obtain the discount code from the web service API, i.e would there be a function call that could tell me which discount code to apply?
I am otherwise attempting to retrieve the discount codes but they can be by Item or By Item Price Class and Customer etc etc which is making the code longer than expected.
Hopeing there is a "GetBestDiscount" facility in the API that could help me?
Thanks,
G
At this moment Acumatica Discount Engine is deactivated for any Web Service call. Due to this fact, entering an order line without any discount will not populate the discount code.
However, at Acumatica University there is the GetSalesPrice.zip customization package made specifically to retrieving the price of an Item for a Customer (attached to the I200 Screen-Based Web Services 5.3 and the I210 Contract-Based Web Services 5.3 sources).
Sample call for Screen-Based API:
Content getSalesPriceSchema = context.GetSchema();
var commands = new Command[]
{
new Value
{
Value = customer,
LinkedCommand =getSalesPriceSchema.RequiredInputParameters.Customer
},
new Value
{
Value = inventoryID,
LinkedCommand =getSalesPriceSchema.RequiredInputParameters.InventoryID
},
getSalesPriceSchema.OutputPrice.Price
};
Content price = context.Submit(commands)[0];
Sample call for Contract-Based API:
GetSalesPriceInquiry priceToBeGet = new GetSalesPriceInquiry
{
Customer = new StringValue { Value = customer },
InventoryID = new StringValue { Value = inventoryID }
};
GetSalesPriceInquiry stockItemPrice = (GetSalesPriceInquiry)soapClient.Put(priceToBeGet);
I tried creating a temporary Sales order line via API Order Entry Screen without saving it as Gabriel suggestion.
I can retrieve the set price no problems but the Discount Percentage and Discount Code is not returned.
The discount percentage returned is zero and the discount Code is blank.
This is because the Acumatica Discount Engine is deactivated for any Web Service call I guess.
Any reason why the Acumatica Discount Engine is deactivated for any Web Service calls?
There is no such API, however you could use the sales order entry screen API to create a temporary sales order, add one line to it and retrieve the set price or discount without saving the order. This will be the most accurate information, since discounts and price can also depend on the date, quantity and also on other products being ordered at the same time.

Updating sharepoint item multi lookup field via odata

I need some help sorting out some syntax for an update to a list item in sharepoint from an application. Here's a rundown on the situation :
There are two lists within this sp site. One list is a products list, and the second list is a pricing. The way these lists are setup however are a 1 to many scheme. One product can have many pricing records. The product then has a column against it that is a look up field that supports multiple values.
Using REST and oData I can query and get the pricing information easily enough now, but my problem is when I need to update the products record to add a price.
with regular lookup fields I normally just set the ID property for the object, then call the update and savechanges methods for that list. With the pricing column however supporting multiple records there is no ID to set, and the field is an array of sorts. Adding the pricing object (list item) and updating and savechanges doesn't actually save. No errors are thrown but the then when viewing the list it isn't actually saving.
How can I add a price lookup to my Product?
I wrote a small method to query through each price and add it's initial price to the product below for testing :
InventoryCatalogDataContext dc = new InventoryCatalogDataContext(_pushinTinSvc);
dc.Credentials = CredentialCache.DefaultCredentials;
List<PricingItem> pricing = (from q in dc.Pricing
select q).ToList<PricingItem>();
foreach (PricingItem price in pricing)
{
var query = (DataServiceQuery<ProductsItem>)
dc.Products
.Expand("Pricing")
.Where(p => p.Id.Equals(price.StockCodeId));
List<ProductsItem> prods = query.ToList<ProductsItem>();
ProductsItem product = prods[0];
product.Pricing.Add(price);
dc.UpdateObject(product);
}
try
{
dc.SaveChanges();
}
catch (Exception ex)
{
string stopHere = ex.Message;
}
I'm not sure if I'm doing something wrong or if this is a bug. If I inspect the item after the SaveChanges, the item still has the pricing item lookup attached, showing a count of 1. At the end of the code block, if I re-query for the product, at that point it even still has the pricing attached. But once the method finishes and returns to the UI, the pricing is no longer attached, the fields are empty when you look at the list in sharepoint, but the version does increment. So I'm a little lost...

Magento upfront payment

For a future project we have been assigned to create a simple concept (inside Magento) that would has to do the following:
A customer has the ability to choose between different shipping methods, one of them being "Ship2Shop", which sends the product to a physical store of choice and the customer has to go an pick it up.
When a customer selects this "ship2shop" shipping method, a certain percentage (eg: 25%) of the total amount has to be paid online (via a pre-defined payment method) and the remaining 75% has to be paid in the physical store when the customer goes and pick up the products he ordered.
How would you go about this?
Idea that we were having is modify the checkout/order session and modify the "grand total" amount (saving the original in a session ofcourse). When the customer is then sent to the external payment processor the "modified grand total" is sent along. Once the customer returns on the magento platform we would modify the order by restoring the original grand total the way it was and updating the total paid and total due amount.
Anyone got any other ideas about this?
EDIT:
After feedback from Anton S below I managed to add an "advance payment total". However Im still having a problem
In the config.xml I have added the following in the tag:
acsystems_advancepayment/total_custom
grand_total
I want my advance payment to show AFTER the grand total, for some reason, magento won't do that...
EDIT2: Collect method
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
$quote = $address->getQuote();
$advancePaymentAmount = 0;
$baseAdvancePaymentAmount = 0;
$items = $address->getAllItems();
if (!count($items)) {
$address->setAdvancePaymentAmount($advancePaymentAmount);
$address->setBaseAdvancePaymentAmount($baseAdvancePaymentAmount);
return $this;
}
$address->setBaseAdvancePayment($address->getGrandTotal()*(0.25));
$address->setAdvancePayment($address->getGrandTotal()*(0.25));
$address->setAdvancePaymentAmount($address->getGrandTotal()*(0.25));
$address->setBaseAdvancePaymentAmount($address->getGrandTotal()*(0.25));
$address->setGrandTotal($address->getGrandTotal() - $address->getAdvancePaymentAmount());
$address->setBaseGrandTotal($address->getBaseGrandTotal()-$address->getBaseAdvancePaymentAmount());
return $this;
}
refer to this thread where adding total objects is explained Magento: adding duties/taxes to a quote during review
Basically you should add your own total object based on your shipping method selection, then it will also be shown in totals as separate row and you can show this in every e-mail or place where totals are exposed
public function collect(Mage_Sales_Model_Quote_Address $address)
{
//this is for the loop that you are in when totals are collected
parent::collect($address);
$quote = $address->getQuote();
//variables for your own object context
$advancePaymentAmount = 0;
$baseAdvancePaymentAmount = 0;
$items = $address->getAllItems();
if (!count($items)) {
$address->setAdvancePaymentAmount($advancePaymentAmount);
$address->setBaseAdvancePaymentAmount($baseAdvancePaymentAmount);
return $this;
}
//calculated based on other total object and don't edit other totals inside your own as your calculations would be always false and so would be next total object in the cycle and so on
$baseAdvancePaymentAmount = $address->getBaseGrandTotal()*(0.25);
$advancePaymentAmount = $address->getQuote()->getStore()->convertPrice($baseAdvancePaymentAmount, false);
//this is just for your own object context
$address->setBaseAdvancePaymentAmount($baseAdvancePaymentAmount);
$address->setAdvancePaymentAmount($advancePaymentAmount);
/*
* this is for the loop that you are in when totals are collected and
* those are set to 0 for each totals collecting cycle
*/
$this->_setBaseAmount($baseAdvancePaymentAmount);
$this->_setAmount($advancePaymentAmount);
return $this;
}
Another option is to change the "grand_total" in your payment module, that way the sessions aren't altered..

Resources