Current Company ID variable in Acumatica? - acumatica

Is it possible to determine the current company ID value for use in custom programming within Acumatica?

The static CurrentCompany property of PXInstanceHelper will return the current company ID:
int companyId = PX.Data.Update.PXInstanceHelper.CurrentCompany;

Related

How can I set the LocationID on the 'Create Shipment' process from the Sales Orders screen?

I have a process that creates records in the Sales Orders screen's Details grid based on two Header user fields: SiteID (Warehouse) and LocationID.
When the 'Create Shipment' process is initiated, the shipment is created which contains the SiteID in the Sales Orders grid - but since there is no locationID in the grid, this 'Create Shipment' process uses some default(?) LocationID, where I'd like to use the Header User field's LocationID.
My question is, how would I intercept this process to set the LocationID to something other than what it's defaulting to?
Thanks...
Update:
Using the virtual method:
SetShipmentFieldsFromOrder(SOOrder order, SOShipment shipment, Nullable<Int32> siteID, Nullable<DateTime> shipDate, String operation, SOOrderTypeOperation orderOperation, Boolean newlyCreated, SetShipmentFieldsFromOrderDelegate baseMethod)
I don't see any way to set the grid value for LocationID (i.e., there is no SOShipLine record to set a value in the virtual method. How would I do this?
There's a virtual method on the SOShipmentEntry graph called SetShipmentFieldsFromOrder, you can override that to update the CustomerLocationID as needed. The create shipment action calls SOShipmentEntry.CreateShipment which inserts the shipment and then calls the SetShipmentFieldsFromOrder method.
The system should be pulling the SOShipment.CustomerLocationID from the SOOrder.CustomerLocationID field by default though.
I believe the question is about defaulting of warehouse locations into the shipment lines and allocations rather than customer locations
Currently, shipment line selects location(s) by the following way
Originally (SelectLocationStatus), it selects location based on their pick priority (smaller value means higher priority)
After this method, the ResortStockForShipmentByDefaultItemLocation is executed. This method puts the default issue location for the item-warehouse combination (InItemSite) at the top of this list regardless of its pick priority.
I believe you should override this method to put the needed location to the top of the list instead of (or ahead of) the default issue location. Here is the code of this method of the SOShipmentEntry class for reference:
protected virtual void ResortStockForShipmentByDefaultItemLocation(SOShipLine newline, List<PXResult> resultset)
if (INSite.PK.Find(this, newline.SiteID)?.UseItemDefaultLocationForPicking != true)
return;
var dfltShipLocationID = INItemSite.PK.Find(this, newline.InventoryID, newline.SiteID)?.DfltShipLocationID;
if (dfltShipLocationID == null)
return;
var listOrderedByDfltShipLocationID = resultset.OrderByDescending(
r => PXResult.Unwrap<INLocation>(r).LocationID == dfltShipLocationID).ToList();
resultset.Clear();
resultset.AddRange(listOrderedByDfltShipLocationID);
}
Important! If we are talking about 21R2 version, there is the "Project-Specific Inventory" (materialManagement) feature which has its own extension of the SOShipmentEntry where some of the shipment creation methods (including the SelectLocationStatus) are overridden. The ResortStockForShipmentByDefaultItemLocation is not overridden, but if the customer uses this feature, I suggest to extend this extension rather than base SOSHipmentEntry:
namespace PX.Objects.PM.MaterialManagement
{
public class SOShipmentEntryMaterialExt : PXGraphExtension<SOShipmentEntry>

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.

PersonID computation (Azure Face API)

I would like to know how the PersonID string (obtained after a call to the PersonGroup Person – Create method of the Face API) is computed. In particular, I would like to know if any information (such as the fields “name” and “userData” for example) can be recovered from it without calling the specific API function Person Group Person – Get.
Thanks in advance.
PersonID string is just a GUID here . If you create a persion, Azure Face service will provide you with an GUID as the ID of that person. As an identifier , PersonID has none business with person details such as “name” and “userData” .
If you want to get some info of a persion , I am afraid using API function Person Group Person – Get is the only way .
If you mean getting the information back that you put into the create() method parameters, yes you can get that from the client.person_group_person.create() results.
The create() method of PersonGroupPerson has the following fields as parameters: person_group_id, name, user_data, custom_headers, raw, and operation_config. So you can add values to those when you create a new PersonGroupPerson. Once this method is called, a Person object is returned with these properties: name, user_data, person_id, persisted_face_ids. So for example, this is what you could do:
# Create a new Person object and add that image to it.
new_person = client.person_group_person.create(person_group_id, name)
img = open(image_name, 'rb')
# Add the new person to your Person object and your person group
face_client.person_group_person.add_face_from_stream(person_group_id, new_person.person_id, img)
print('New Person Created:', new_person.name)
In the above example, you get person_id and name from the results of your create() call. So, whatever parameters you add in create(), can be retrieved from the result.
However, this is just general Person information, you have not yet added images (faces) of this person to this Person object yet, unless you call add_face_from_stream() or add_face_from_url().
If you are wondering how the person ID is created, Microsoft has some of their source code available in Github.
Person Group Person operations: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/cognitiveservices/azure-cognitiveservices-vision-face/azure/cognitiveservices/vision/face/operations/_person_group_person_operations.py
Person class (line 1213): https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/cognitiveservices/azure-cognitiveservices-vision-face/azure/cognitiveservices/vision/face/models/_models.py

Am I designing and constructing my value objects correctly?

Sorry in advance if this question is unclear. Please tell me what to change to make it a better question.
I am currently maintaining a C# WinForm system where I'm trying to learn and use DDD and CQRS principles. Vaughn Vernon's Implementing Domain Driven Design is my main DDD reference literature.
The system currently uses legacy code which makes use of Data Aware Controls.
In the Asset Inventory Context, i have designed my aggregate root Asset which composes of multiple valueObjects which are standard entries in the system:
In this Context, i'm trying to implement a use case where the user can manually register an Asset to the system.
My current implementation is the following:
From Presentation Layer:
Upon loading the RegisterAssetForm.cs it loads the existing standard entry lists of Group, ItemName, etc. through the Data Aware controls, all consisting of data rows with columnsid: int and name: string.
When the user selects the desired ItemName, Group, PropertyLevel, Department, and Category, then clicks save, a command is performed:
RegisterAssetForm.cs
...
AssetInventoryApplicationService _assetInventoryServ;
...
void btnSave_Click(object sender, EventArgs e)
{
int itemNameId = srcItemName.Value // srcItemName is a custom control whose Value = datarow["id"]
int groupId = srcGroup.Value;
string categoryId = srcCategory.Value;
string departmentId = srcDepartment.Value;
string propLvlId = srcPropLevel.Value;
...
RegisterAssetCommand cmd = new RegisterAssetCommand(itemNameId, groupId, categoryId, departmentId, propLvlId);
_assetInventoryServ.RegisterAsset(cmd);
...
}
From Application Layer:
The AssetInventoryApplicationService depends on domain services.
AssetInventoryApplicationService.cs
...
IAssetRepository _assetRepo;
...
public void RegisterAsset(RegisterAssetCommand cmd)
{
...
AssetFactory factory = new AssetFactory();
AssetID newId = _assetRepo.NextId();
Asset asset = factory.CreateAsset(newId, cmd.ItemNameId, cmd.PropertyLevelId,
cmd.GroupId, cmd.CategoryId, cmd.DepartmentId);
_assetRepo.Save(asset);
...
}
From Domain Layer:
AssetFactory.cs //not my final implementation
...
public class AssetFactory
{
...
public Asset CreateAsset(AssetID id, int itemNameId, int propLvlId, int groupId, int categoryId, int departmentId)
{
ItemName itemName = new ItemName(itemNameId);
PropertyLevel propLvl = new PropertyLevel(propLvlNameId);
Group group = new Group(groupNameId);
Category category = new Category(categoryNameId);
Department department = new Department(departmentNameId);
return new Asset(id, itemName, propLvl, group, category, deparment);
}
...
}
Sample table of what fills my value objects
+------------+--------------+
| CategoryID | CategoryName |
+------------+--------------+
| 1 | Category1 |
| 2 | Category2 |
| 3 | Category3 |
| 4 | Category4 |
| 5 | Category5 |
+------------+--------------+
I know domain models must be persistence-ignorant that's why i intend to use surrogate identites (id field) in Layer Supertype with my valueobject to separate the persistence concern from the domain.
The main property to distinguish my value objects is their Name
From the presentation layer, i send the standard entry value as integer id corresponding to primary keys through a command to the application layer which uses domain services.
Problem
* Is it right for me to pass the standard entry's id when creating the command, or should I pass the string name?
* If id is passed, how do i construct the standard entry value object if name is needed?
* If name is passed, do i need to figure out the id from a repository?
* Or am I simply designing my standard entry value objects incorrectly?
Thanks for your help.
It looks to me that you may be confusing a Value Object and an Entity.
The essential difference is that an Entity needs an Id but a VO is a thing (rather than a specific thing). A telephone number in a CRM would likely be a VO. But it would likely be an Entity in if you are a telephone company.
I have an example of VO in this post which you may find helpful - you can get it here
To answer your 'Problems' more specifically:
If you are creating some entity then it can be advantageous to pass in the id to a command. That way you already know what the id will be.
You shouldn't be able to create an invalid value object.
Why can't you pass in the name and the ID? Again - not sure this is relevant to a Value Object
I think you have designed them incorrectly. But I can't be sure because I don't know your specific domain.
Hope this helps!

Get SPListItem in another format

I want to get different Rows from an SPListItem. I'll show you my problem with an example.
This code
Console.WriteLine(SPItemName["Created By"]);
or
Console.WriteLine(SPItemName["Created By"].ToString);
returns "8;UserName" (8 is the User ID).
If I look up the row in SharePoint Designer, i can choose even a format for this data field.
So i could get the html code of this field.
How to set the format (like html code or text) of a datafield in c#?
thanks
Use Either SPFieldLookupValue
If you need just the username, use SPFieldLookupValue to seperate id from value:
var userValue = new SPFieldLookupValue(SPItemName["Created By"] as string)
Then you can:
userValue.LookupValue to return UserName
userValue.LookupId to return Id
Or SPFieldUserValue
Or better yet, you can create SPFieldUserValue object to access any other user properties like email, login name, etc..
SPFieldUserValue objUserFieldValue = new SPFieldUserValue(web, SPItemName["Created By"].ToString());
Afterwards you can use:
objUserFieldValue.User.LoginName;
objUserFieldValue.User.Name;
objUserFieldValue.User.ID;
objUserFieldValue.User.Groups;
objUserFieldValue.User.Roles;
objUserFieldValue.User.Email;
objUserFieldValue.User.Sid;
objUserFieldValue.User.UserToken;
http://www.sharepointkings.com/2009/04/spfielduservalue-and.html
Note: to create SPFieldUserValue you must pass reference to web, that's because SharePoint has to get additional user information from user information list to construct SPFieldUserValue object.

Resources