Creating Customer Location from Sales Order Screen - acumatica

I want to create Customer Location from Sales Order Ship to Contact and Address. The following code works fine when order is saved and a new location is created.
The problem is: After I created a new order with order type “SO” and save the location, I go back to the Order Entry point screen, then click add new order. In new order screen, I select order type “QT” and select the same customer, the ADDRESS tab info are all blank. If I click save button, I got the error message “Error: ‘CustomerID’cannot be empty”. It seems the Customer is not selected. I have to select Customer again.
This only happens when location is saved, and create a new order with different order type and same customer. If I don't go back to the Order Entry point screen, and click + from Sales Order screen directly, it works fine.
namespace PX.Objects.SO
{
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class SOOrderEntry_CBIZExtension : PXGraphExtension<PX.Objects.SO.SOOrderEntry>
{
#region Event Handlers
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
SOShippingContact shippingContact = Base.Shipping_Contact.Select();
SOShippingAddress shippingAddress = Base.Shipping_Address.Select();
SOOrder order = Base.CurrentDocument.Select();
SOOrderExt orderExt = order.GetExtension<SOOrderExt>();
if (orderExt != null && orderExt.UsrSaveLocation == true
&& !(string.IsNullOrEmpty(shippingContact.FullName)))
{
// get LOCATION segment length
Segment seg = SelectFrom<Segment>.Where<Segment.dimensionID.IsEqual<#P.AsString>>.View.
SelectSingleBound(Base, null, "LOCATION");
int locationLength = 10;
if (seg != null)
locationLength = seg.Length.Value;
// Get Location Name
string[] nameList = shippingContact.FullName.Split(' ');
string locationFirstName = nameList[0];
if (locationFirstName.Length > locationLength)
locationFirstName = locationFirstName.Substring(0, locationLength);
// Check if Customer location already exist
Location location = SelectFrom<Location>.Where<Location.bAccountID.IsEqual<#P.AsInt>.
And<Location.locationCD.IsEqual<#P.AsString>>>.View.
SelectSingleBound(Base, null, Base.Document.Current.CustomerID, locationFirstName);
if (location == null)
{
// New Customer location
// Create Location Instance
LocationMaint locationMaint = PXGraph.CreateInstance<CustomerLocationMaint>();
var loc = (Location) locationMaint.Location.Cache.CreateInstance();
loc.BAccountID = Base.Document.Current.CustomerID;
locationMaint.Location.Cache.SetValueExt<Location.locationCD>(loc, locationFirstName);
loc.LocType = LocTypeList.CustomerLoc;
loc = locationMaint.Location.Insert(loc);
loc.Descr = shippingContact.FullName;
loc = locationMaint.Location.Update(loc);
if (shippingContact.OverrideContact == true)
{
loc.OverrideContact = true;
loc = locationMaint.Location.Update(loc);
string firstName = nameList[0];
string lastName = "";
if (nameList.Length > 1)
lastName = nameList[1];
Contact cont = locationMaint.Contact.Current;
cont.FullName = shippingContact.FullName;
cont.FirstName = firstName;
cont.LastName = lastName;
cont.Attention = shippingContact.Attention;
cont.Phone1 = shippingContact.Phone1;
cont.Phone1Type = shippingContact.Phone1Type;
cont.EMail = shippingContact.Email;
cont = locationMaint.Contact.Update(cont);
}
if (shippingAddress.OverrideAddress == true)
{
loc.OverrideAddress = true;
loc = locationMaint.Location.Update(loc);
var addr = locationMaint.Address.Current;
addr.AddressLine1 = shippingAddress.AddressLine1;
addr.AddressLine2 = shippingAddress.AddressLine2;
addr.City = shippingAddress.City;
addr.CountryID = shippingAddress.CountryID;
addr.State = shippingAddress.State;
addr.PostalCode = shippingAddress.PostalCode;
addr = locationMaint.Address.Update(addr);
}
// Save the customer location
locationMaint.Actions.PressSave();
}
}
// Call bas method
baseMethod();
Base.Shipping_Contact.Cache.Clear();
Base.Shipping_Address.Cache.Clear();
Base.Document.View.RequestRefresh();
Base.Document.Cache.IsDirty = false;
}
#endregion
}
}

Related

Error While creating Sales Order from Sales Quote (CR304500)

I have created a Action called "CREATE SO" in Sales Quote(CR304500) screen to create Sales Order. I have created a ComboBox udf "Sales Order Type" to select "Doc Type" of the Sales Order to be created.
When I am selecting DocType as "SO", its giving error "Unit
Conversion is missing". (see pic)
When I am selecting any other DocType it gives an error "RevisionID
cannot be empty".(see pic)
"SO" is the default Order Type in SO Preferences. I am unable to track the error using debugger. Please suggest. Thanks. Following is my code.
#region Create Sales Order
public PXAction<CRQuote> createSalesOrder;
[PXUIField(DisplayName = "Create SO", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXProcessButton(CommitChanges = true)]
public IEnumerable CreateSalesOrder(PXAdapter adapter)
{
QuoteMaint graphObject = PXGraph.CreateInstance<QuoteMaint>();
foreach (CRQuote quote in adapter.Get())
{
//Create resultset for Quote Details
PXResultset<CROpportunityProducts> PXSetLine = PXSelect<CROpportunityProducts,
Where<CROpportunityProducts.quoteID,
Equal<Required<CROpportunityProducts.quoteID>>>>.Select(this.Base, quote.QuoteID);
List<CROpportunityProducts> QuoteList = new List<CROpportunityProducts>();
foreach (CROpportunityProducts line in PXSetLine)
{
QuoteList.Add(line);
}
bool var_orderCreated = false;
bool erroroccured = false;
string ErrMsg = "";
SOOrderEntry orderGraphObjet = PXGraph.CreateInstance<SOOrderEntry>();
SOOrder orderHeaderObject = new SOOrder();
QuoteMaint currGRPH = PXGraph.CreateInstance<QuoteMaint>();
CRQuoteExt _quoteExt = PXCache<CRQuote>.GetExtension<CRQuoteExt>(quote);
var Extension = this.Base.GetExtension<QuoteMaint_Extension>();
orderHeaderObject = orderGraphObjet.CurrentDocument.Insert(orderHeaderObject);
BAccount customer = PXSelect<BAccount, Where<BAccount.bAccountID, Equal<Current<CRQuote.bAccountID>>>>.Select(this.Base, quote.BAccountID);
if (customer.Type == "CU")
{
orderHeaderObject.CustomerID = quote.BAccountID;
orderHeaderObject.CustomerLocationID = quote.LocationID;
}
else
{
throw new PXException("Business Account not converted to Customer yet");
}
if (quote.CuryProductsAmount != 0)
{
orderHeaderObject.CuryOrderTotal = quote.CuryProductsAmount;
}
else
{
throw new PXException("Total cannot be 0");
}
orderHeaderObject.CuryOrderTotal = quote.CuryProductsAmount;
orderHeaderObject.CuryTaxTotal = quote.CuryTaxTotal;
orderHeaderObject.OrderDesc = quote.Subject;
orderHeaderObject.OrderType = _quoteExt.UsrOrderNbr;
orderGraphObjet.Document.Update(orderHeaderObject);
orderGraphObjet.CurrentDocument.Current = orderHeaderObject;
orderGraphObjet.Actions.PressSave();
orderHeaderObject = orderGraphObjet.CurrentDocument.Current;
foreach (CROpportunityProducts tran in QuoteList)
{
SOLine transline = new SOLine();
orderGraphObjet.Transactions.Insert(transline);
transline.OrderNbr = orderHeaderObject.OrderNbr;
transline.BranchID = orderHeaderObject.BranchID;
transline.InventoryID = tran.InventoryID;
transline.TranDesc = tran.Descr;
transline.UOM = tran.UOM;
transline.OrderQty = tran.Quantity;
transline.SiteID = tran.SiteID;
transline.CuryUnitPrice = tran.CuryUnitPrice;
transline.CuryExtPrice = tran.CuryExtPrice;
transline.CuryLineAmt = tran.CuryAmount;
CROpportunityProductsExt xOppProductExt = PXCache<CROpportunityProducts>.GetExtension<CROpportunityProductsExt>(tran);
SOLineExt _soLext = PXCache<SOLine>.GetExtension<SOLineExt>(transline);
_soLext.UsrXSeqID = xOppProductExt.UsrXSequenceID;
_soLext.UsrXGroupID = xOppProductExt.UsrXGroupID;
_soLext.UsrInternalRemk = xOppProductExt.UsrInternalRemk;
orderGraphObjet.Transactions.Update(transline);
}
orderGraphObjet.Actions.PressSave(); //This is the line where both the error is showing
if (orderGraphObjet != null && orderHeaderObject != null)
{
orderGraphObjet.Document.Current = orderHeaderObject;
throw new PXRedirectRequiredException(orderGraphObjet, "Document") { Mode = PXBaseRedirectException.WindowMode.NewWindow };
}
yield return quote;
}
}
############## DAC FIELD #####################
[PXDBString(50)]
[PXUIField(DisplayName = "Sales Order Type")]
[PXDefault()]
[PXStringList(new string[] { "SO", "SP", "SS" }, new string[] { "SO - Sales Order", "SP - Sales Of Project", "SS - Sales Of Service" })]
public virtual string UsrOrderNbr { get; set; }
public abstract class usrOrderNbr : PX.Data.BQL.BqlString.Field<usrOrderNbr> { }
I would suggest that when you insert your new objects into the cache, that you insert an object with it's key elements already entered. For instance, I would add CustomerID and CustomerLocationID to orderHeaderObject and then Insert it into the Document cache. When you do that, the Acumatica validation will fire and all the defaults will be set in your document before you try and edit them. Same goes for your line level object, I think that's the reason you're getting both errors. Also, I notice you trying to set the value for a few calculated fields. If possible I would try and leave these to calculate as designed.

Creating Customer Location

My requirement is to create a customer location part of downloading order from 3rd party shopping cart.
I have tried this below code and It is not saving any location and also not raising any error.
private static void CreateCustomerLocation(Customer cust, string locationcode, OrderDTO ord, OrderDownloadActivityEntry grp)
{
try
{
LocationMaint graph = CustomerLocationMaint.CreateInstance<CustomerLocationMaint>();
SelectedLocation loc = new SelectedLocation();
loc.BAccountID = cust.BAccountID;
loc.LocationCD = locationcode;
loc.Descr = ord.CustomerLocationName;
loc.IsContactSameAsMain = false;
loc.IsAddressSameAsMain = false;
graph.Location.Insert(loc);
Contact contact = new Contact();
contact.Attention = ord.OrderCustomerContactName;
contact.Phone1 = ord.OrderCustomerContactPhone;
contact.DisplayName = ord.CustomerLocationName;
contact.LastName = ord.OrderCustomerContactName;
contact = graph.Contact.Update(contact);
Address address = new Address();
address.AddressLine1 = ord.OrderShippingLocationAddress1;
address.AddressLine2 = ord.OrderShippingLocationAddress2;
address.City = ord.OrderShippingLocationCity;
address.State = ord.OrderShippingLocationState;
address.PostalCode = ord.OrderShippingLocationZip;
address.CountryID = "US";
contact = graph.Contact.Update(contact);
address = graph.Address.Update(address);
loc.DefAddressID = address.AddressID;
loc.DefContactID = contact.ContactID;
graph.Location.Update(loc);
graph.Save.Press();
}
catch(Exception e)
{
grp.AddLogData(SessionID, "Create Location", "Create Location falied", null, null, e.StackTrace);
}
}
I am not able to figure out where i am making mistake. any suggestion for this issue?
Update
I have tried the following code and I am getting the following error
CARAccountLocationID' cannot be empty.
private static void CreateCustomerLocation(Customer cust, string locationcode, OrderDTO ord, OrderDownloadActivityEntry grp)
{
try
{
LocationMaint graph = PXGraph.CreateInstance<CustomerLocationMaint>();
graph.BusinessAccount.Current = PXSelect<BAccount, Where<BAccount.bAccountID, Equal<Required<BAccount.bAccountID>>>>.Select(graph, cust.BAccountID);
var newLocation = (Location)graph.Location.Cache.CreateInstance();
var locType = LocTypeList.CustomerLoc;
newLocation.LocType = locType;
graph.Location.Insert(newLocation);
var loc = (Location)graph.Location.Cache.CreateCopy(graph.Location.Current);
Contact contact = graph.Contact.Cache.CreateCopy(graph.Contact.Current) as Contact;
contact.Attention = ord.OrderCustomerContactName;
contact.Phone1 = ord.OrderCustomerContactPhone;
contact.DisplayName = ord.CustomerLocationName;
contact.LastName = ord.OrderCustomerContactName;
contact = graph.Contact.Update(contact);
Address address = graph.Address.Cache.CreateCopy(graph.Address.Current) as Address;
address.AddressLine1 = ord.OrderShippingLocationAddress1;
address.AddressLine2 = ord.OrderShippingLocationAddress2;
address.City = ord.OrderShippingLocationCity;
address.State = ord.OrderShippingLocationState;
address.PostalCode = ord.OrderShippingLocationZip;
address.CountryID = "US";
contact = graph.Contact.Update(contact);
address = graph.Address.Update(address);
contact.DefAddressID = address.AddressID;
loc.IsAddressSameAsMain = false;
loc.IsContactSameAsMain = false;
loc.IsAPAccountSameAsMain = true;
loc.IsAPPaymentInfoSameAsMain = true;
loc.IsARAccountSameAsMain = true;
loc.LocationCD = locationcode;
loc.Descr = ord.CustomerLocationName;
loc = graph.Location.Update(loc);
loc.BAccountID = cust.BAccountID;
graph.Location.Cache.RaiseFieldUpdated<Location.isARAccountSameAsMain>(loc, null);
if (loc.CARAccountLocationID == null)
loc.CARAccountLocationID = cust.DefLocationID;
graph.Location.Update(loc);
graph.Save.Press();
}
catch(Exception e)
{
grp.AddLogData(SessionID, "Create Location", "Create Location falied", null, null, e.StackTrace);
}
}
CARAccountLocationID is the LocationID of the MAIN location for a given BAccount/Customer. It is used by the business logic when setting GLAccounts.SameAsDefaultLocationS on screen AR303020.
I've seen the "'CARAccountLocationID' cannot be empty." error when creating a location without first setting the Customer.
The resolution was to first set the customer, then set SameAsDefaultLocationS, then set the rest of the fields.
In the screen API order of operations matters.
In your case you might need to directly set loc.CARAccountLocationID to the LocationID of the customer's MAIN location.

Add note to custom object

I have tried everything I can find on the net and in the existing code, but I cannot get a note added to the notes table and attached to my custom table row. I am in a real bind trying to get this note attached. Any help will be greatly appreciated.
Here is the note id def:
#region NoteID
public abstract class noteID : PX.Data.IBqlField { }
protected Guid? _NoteID;
[PXNote()]
public virtual Guid? NoteID { get; set; }
#endregion
Here is the code to insert the row and attach the note:
//Retrieve EDI Document remittance
foreach (LingoSearchResults ediRemit in docRemits)
{
resRemit = lingo.RetrieveRemit(ediRemit.documentId, docType);
partnerCustomerMap pcmap = lstPartnerCustomer.Find(delegate (partnerCustomerMap pcm)
{ return pcm.partner == resRemit.DataRemit.partner; });
int newRemittanceId = 0;
var remittance = new EDRemittance();
//Set all field values
remittance.Status = "A";
remittance.Type = resRemit.DataRemit.type;
remittance.DocumentId = resRemit.DataRemit.documentId;
remittance.RecordId = resRemit.DataRemit.recordId;
remittance.TagId = resRemit.DataRemit.tagId;
remittance.Account = resRemit.DataRemit.account;
remittance.PartnerId = resRemit.DataRemit.partner;
remittance.DocumentNumber = resRemit.DataRemit.documentNumber;
remittance.SenderType = resRemit.DataRemit.senderType;
remittance.PaymentNumber = resRemit.DataRemit.paymentNumber;
remittance.PaymentFormat = resRemit.DataRemit.paymentFormat;
remittance.PaymentReason = resRemit.DataRemit.paymentReason;
strDate = resRemit.DataRemit.remitDate.ToString();
if (DateTime.TryParseExact(strDate, "yyyyMMdd",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out tempDate))
remittance.RemitDate = tempDate;
else
remittance.RemitDate = DateTime.Today;
remittance.CurrencyEntity = resRemit.DataRemit.currencyEntity;
remittance.DepartmentNumber = resRemit.DataRemit.departmentNumber;
if (DateTime.TryParse(strDate, out tempDate))
remittance.ReceiveDate = tempDate;
else
remittance.ReceiveDate = DateTime.Today;
remittance.HandlingCode = resRemit.DataRemit.handlingCode;
remittance.RemitTotal = resRemit.DataRemit.remitTotal;
remittance.DetailLineCount = resRemit.DataRemit.detailLineCount;
remittance.BatchNumber = resRemit.DataRemit.batchNumber;
remittance.ReceiverType = resRemit.DataRemit.receiverType;
remittance.BatchStatus = resRemit.DataRemit.batchStatus;
remittance.PaymentMethod = resRemit.DataRemit.paymentMethod;
remittance.CurrencyCode = resRemit.DataRemit.currencyCode;
remittance.PaymentStatus = resRemit.DataRemit.paymentStatus;
remittance.Vendor = resRemit.DataRemit.vendor;
remittance.RemitNumber = resRemit.DataRemit.remitNumber;
//Insert new row, save, and retrieve new Id value
remitGraph.Remittance.Insert(remittance);
remitGraph.Persist();
newRemittanceId = (int)remitGraph.Remittance.Current.RemittanceNbr;
//Add notes for remittance
noteText = "Remit level note";
foreach (EdiNote note in resRemit.DataRemit.notes)
{
noteText += note.type + ": " + note.note + '\n';
}
if (noteText != "")
{
PXNoteAttribute.GetNoteID<EDRemittance.noteID>(remitGraph.Remittance.Cache, remittance);
PXNoteAttribute.SetNote(remitGraph.Remittance.Cache, remittance, noteText);
//remitGraph.Persist();
}
I would try the following changes
remittance = remitGraph.Remittance.Insert(remittance);
//this saves the object to the cache and gets things like Noteid generated. On the
//return trip this data is available
//remitGraph.Persist();
//PXNoteAttribute.GetNoteID<EDRemittance.noteID>(remitGraph.Remittance.Cache, remittance);
PXNoteAttribute.SetNote(remitGraph.Remittance.Cache, remittance, noteText);
remittance = remitGraph.Remittance.Update(remittance)
//at the end do an Actions.PressSave();

Add Join in BQLCommand

I would like to join the following statement with EPEmployee table on EPEmployee's BAccountID with FSAppointmentEmployee's EmployeeID column then put where condition on EPEmployee's UserID with currently logged in employee's user id in the current BQLCommand for PXAdapter, so that I can see the list of appointments that are assigned to current employee only.
public static PXAdapter PrepareCustomNavAdapter(PXAction action, PXAdapter adapter, bool prevNextAction = false)
{
var select = adapter.View.BqlSelect;
select = select
.WhereAnd<Where<EPEmployee.userID,Equal<AccessInfo.userID>>>()
.OrderByNew<OrderBy<
Desc<FSAppointment.createdDateTime,
Desc<FSAppointment.srvOrdType,
Desc<FSAppointment.refNbr>>>>>();
var newAdapter = new PXAdapter(new PXView(action.Graph, true, select))
{
MaximumRows = adapter.MaximumRows
};
object current = action.Graph.Views[action.Graph.PrimaryView].Cache.Current;
if (prevNextAction)
{
var sortColumns = new string[adapter.SortColumns.Count() + 1];
adapter.SortColumns.CopyTo(sortColumns, 1);
sortColumns[0] = "CreatedDateTime";
newAdapter.SortColumns = sortColumns;
var descendings = new bool[adapter.Descendings.Count() + 1];
adapter.Descendings.CopyTo(descendings, 1);
descendings[0] = true;
newAdapter.Descendings = descendings;
var searches = new object[adapter.Searches.Count() + 1];
adapter.Searches.CopyTo(searches, 1);
if (current != null && current is FSAppointment)
searches[0] = ((FSAppointment)current).CreatedDateTime;
newAdapter.Searches = searches;
}
else if (current != null)
{
adapter.Currents = new object[] { current };
}
return newAdapter;
}
So that, only these two employees would be able to see that appointment.
Thank you.
AccessInfo is a Singleton, you should decorate it with Current class:
Where<EPEmployee.userID, Equal<Current<AccessInfo.userID>>>

PXSelect returns null after record inserted

I am creating a customer in code. Straight after I create the customer I perform a PXSelect to retrieve the customer by the acctCd. But it returns null everytime. Even though I have checked to the database and verified it exists?
I'm guessing this is something to do with the cache how do I refresh this.
Here is my PXSelect
PXSelect<PX.Objects.AR.Customer, Where<PX.Objects.AR.Customer.acctCD, Equal<Required<PX.Objects.AR.Customer.acctCD>>>>.Select(this, id);
Here is my code that add customer
private PX.Objects.AR.Customer UpdateContact(ContactRead rexContact, PX.Objects.AR.Customer m, string customerClassID, bool insert = true)
{
PX.Objects.CR.Contact defContact = null;
PX.Objects.AR.CustomerMaintInherit graph = PXGraph.CreateInstance<PX.Objects.AR.CustomerMaintInherit>();
graph.Clear(PXClearOption.ClearAll);
//Add Customer and BAccount Records
graph.BAccount.Current = m;
m.AcctCD = "V" + rexContact._id;
m.AcctName = rexContact.system_search_key;
m.Type = "CU";
if (insert) {
m = graph.BAccount.Insert(m);
defContact = graph.DefContact.Current;
}
else {
defContact = PXSelect<PX.Objects.CR.Contact, Where<PX.Objects.CR.Contact.contactID, Equal<Required<PX.Objects.CR.Contact.contactID>>>>.Select(this, m.DefContactID);
graph.DefContact.Current = defContact;
}
//Update Default Contact Record
defContact.ContactType = "AP";
defContact.FullName = rexContact.system_search_key;
if (rexContact._related.contact_emails != null)
{
if (rexContact._related.contact_emails.Length > 0)
{
defContact.EMail = (from e in rexContact._related.contact_emails where e.email_primary == true select e.email_address).FirstOrDefault();
}
}
if (rexContact._related.contact_phones != null)
{
if (rexContact._related.contact_phones.Length > 0)
{
defContact.Phone1 = (from e in rexContact._related.contact_phones where e.phone_primary == true select e.phone_number).FirstOrDefault();
}
}
defContact = graph.DefContact.Update(defContact);
//Change customer class to vendor
m.CustomerClassID = customerClassID;
m = (PX.Objects.AR.Customer)graph.BAccount.Update(m);
graph.Actions.PressSave();
return m;
}
Consider usage PXSelectReadonly. It will try to retrieve value directly from db without usage of cache. Another option is to create instance of graph, with needed view, and through that graph ask db with PXSelect

Resources