Optaplanner VRP with multiple customers per location but shared location capacity - optaplanner

I am new to OptaPlanner. I have a pickup and delivery problem with a few types of goods that have to be redistributed across different stations in a city in an efficient way. Each station has a maximum overall capacity (assume that each item consumes one unit of capacity).
To this end I am expanding upon the TWVRP, trying to create a Station class that maps a location to a list of customers and vice versa, so that I can track the supply & demand totals across all customers at a location, and how much capacity is left there. I added the list of stations to the VehicleRoutingSolution as follows:
#ProblemFactCollectionProperty
public List<Station> getStationList() {
return stationList;
}
public void setStationList(List<Station> stationList) {
this.stationList = stationList;
}
And the relevant code for the Station itself looks like:
#XStreamAlias("VrpStation")
#DeepPlanningClone
#PlanningEntity
public class Station extends AbstractPersistable {
protected Location location;
protected List<Customer> customers;
protected Integer capacity;
protected Map<WareType, Integer> current;
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public List<Customer> getCustomers() {
return customers;
}
public void setCustomers(List<Customer> customers) {
this.customers = customers;
}
public Integer getCapacity() {
return capacity;
}
public void setCapacity(Integer capacity) {
this.capacity = capacity;
}
public Map<WareType, Integer> getCurrentWares() {
Map<WareType, Integer> current = new HashMap<WareType, Integer>();
for (Customer customer : getCustomers()) {
for (WareType wt: customer.getCurrent().keySet()) {
int old = current.containsKey(wt) ? current.get(wt) : 0;
current.put(wt, old + customer.getCurrent().get(wt));
}
}
return current;
}
}
I also added a reference to the station to the Customer.
#PlanningEntity
#XStreamAlias("VrpCustomer")
#XStreamInclude({
TimeWindowedCustomer.class
})
public class Customer extends AbstractPersistable implements Standstill {
protected Station station;
public Station getStation() {
return station;
}
public void setStation(Station station) {
this.station = station;
}
#Override
public Location getLocation() {
return getStation().getLocation();
}
// ... same old same old
}
Ive set it up so that each customer either requests or demands items of one type. The station itself does not change, but of course the customers do, hence the #DeepPlanningClone annotation.
However when I run the optaplanner example with these adjustments, I seem to be getting updates to Customers that were never visited according to my solution. I have a suspicion that this has to do with the way the Station and its customers are cloned, but I am not sure what the exact problem is or how I can solve it. What am I doing wrong?

Related

POJO information lost during RPC call (GWT)

I am having issues with RPC calls and GWT. Essentially, I have a Person class (common code between client and server) that is created in the client side web code, sent to the server code via an RPC call, and then saved to a DB (OrientDB). I have verified that the following work:
RPC call - I am able to send info to the server and retrieve info from the server
save to DB - have verified that a Person object is saved to the DB
Where I am having issues is the transfer of the POJO from the client to the server. I have verified that the POJO's properties are intact right before it is sent to the server, however, the object passed to the server contains null values for all properties. Essentially, the class is transferred but the information is not. It then saves to the DB, but obviously without any relevant information contained within it.
I will copy what I feel is relevant below, please let me know what else I can provide to make this problem easier to identify. Note these are still in a testing state, so mind the comments :)
Any idea why my POJO's information is being lost in translation?
Person object, followed by the abstract class it inherits from:
public class Person extends org.matesweb.shared.AbsPerson implements Serializable
{
#Id
private String id; // DON'T CREATE GETTER/SETTER FOR IT TO PREVENT THE CHANGING BY THE USER APPLICATION,
// UNLESS IT'S NEEDED
//sets new user details
public void setPerson(String fIrstName, String mIdInit, String lAstName, String email, String password)
{
firstName = fIrstName;
middleInitial = mIdInit;
lastName = lAstName;
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public Object getId()
{
String tmp;
tmp = id.toString();
return tmp;
}
//end class
}
public class AbsPerson implements Serializable
{
String firstName;
String middleInitial;
String lastName;
// public sys.Login login;
public org.matesweb.shared.Group[] groups;
private org.matesweb.shared.Purchase[] purchases;
/*this method adds a new purchase to the purchases variable*/
/* public void addPurchase(float price, String description)
{
people.Purchase newPurchase = new people.Purchase(login, price, description);
}
*/
/*adds a person to a group by comparing the passed in group ID and PWD*/
public void addGroup(String groupID, String groupPWD)
{
//compare group ID with group PWD to add a user to the group
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public String getFirstName()
{
return firstName;
}
public void setFirstName(String name)
{
firstName = name;
}
public String getMiddleInitial()
{
return middleInitial;
}
public void setMiddleInitial(String midInit)
{
middleInitial = midInit;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String ln)
{
lastName = ln;
}
/*
public sys.Login getLogin()
{
return login;
}
public void setLogin(sys.Login log)
{
login = log;
}
*/
public org.matesweb.shared.Group[] getGroups()
{
return groups;
}
public void setGroups(org.matesweb.shared.Group[] gro)
{
groups = gro;
}
public org.matesweb.shared.Purchase[] getPurchases()
{
return purchases;
}
public void setPurchases(org.matesweb.shared.Purchase[] purch)
{
purchases = purch;
}
}
Service
package org.matesweb.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import org.matesweb.shared.Person;
#RemoteServiceRelativePath("peopleService")
public interface PeopleService extends RemoteService {
//test services
String stringTest(String outgoingString);
Person getPerson(String persId);
//production services
String savePerson(Person p);
}
ServiceAsync
import com.google.gwt.user.client.rpc.AsyncCallback;
import org.matesweb.shared.Person;
public interface PeopleServiceAsync
{
//tests
void stringTest(String outgoingString, AsyncCallback<String> incomingString);
void getPerson(String persId, AsyncCallback<Person> retPerson);
//production services
void savePerson(Person p , AsyncCallback<String> st);
}
ServiceImpl call for this particular method:
//production calls
#Override
public String savePerson(Person p) {
String st = ioObj.saveObj(p);
if(st.equals("Success")){
return "Your information has been saved successfully!";
} else{
return "Something has gone wrong on our end... Sorry! Error:<br /> " + st;
}
}
and finally, the call itself
private static void savePerson(Person p)
{
// Initialize the service proxy.
if (peopleSvc == null) {
peopleSvc = GWT.create(PeopleService.class);
}
//resets status
st="";
// Set up the callback object.
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
st = caught.getMessage();
Label stLabel= new Label(st);
personTable.setWidget(3,1,stLabel);
}
#Override
public void onSuccess(String result) {
st = result;
HTML stLabel= new HTML(st);
joinPanel.add(stLabel);
}
};
// Make the call to the people service.
peopleSvc.savePerson(p, callback);
}
I was able to fix this issue by implementing GWT's IsSerializable interface. I also removed the Serializable interface from the Person class and let it inherit IsSerializable from the abstract class it inherits from.

Issue with Process Delegate after implementing a non-persistent DAC

I am struggling with getting my Process Delegate to wire up correctly after implementing the advice pointed out in this ticket Implementing a DAC with no persisted fields. The processing page for the most part now behaves as we need. The records autoload based off of data pulled in via a ReST web service and we are not persisting any data to the ERP until the processing buttons are used. The issue I am having now is the SetProcessDeligate method is now not doing anything when I hit the process buttons. When I wire the older code into place that has one persistent field and requires a user to hit a load button the Process and Process All buttons work as expected.
I have created this screencast to walk through and give visual context to the issue. https://www.dropbox.com/s/j8vnp8p3556nj1e/issue%20with%20the%20PXProcessing%20page%20not%20wiring%20into%20the%20event%20handler%202019-01-03_12-57-50.mp4?dl=0
As always I am very grateful for any help. Thank you
Robert
//This is how my Graph is defined now.
public class CtpPaymentProcess : PXGraph<CtpPaymentProcess>
{
//public PXAction<CtpPayment> checkForC2PPayments;
public PXSetup<CtpSetup> setup;
public PXProcessing<CtpPayment> Payments;
public QueryPaymentsResponseViewModel paymentsFromCtpServer { get; internal set; }
public IEnumerable payments()
{
paymentsFromCtpServer = CtpAcumatica.CheckForAllNewPayments(100);
PXTrace.WriteInformation("Processing " + (paymentsFromCtpServer.Payments.Count) + " paymentsFromCtpServer");
if (paymentsFromCtpServer.Payments != null)
{
// Loop processing each payment returned from the gateway, storing the
// information into non persisted cache.
foreach (var payment in paymentsFromCtpServer.Payments)
{
if (!payment.IsMarkedRetrieved)
{
yield return BuildCtpPayment(payment);
}
}
}
}
private CtpPayment BuildCtpPayment(PaymentViewModel payment)
{
var customer = (Customer)PXSelect<Customer,
Where<Customer.bAccountID, Equal<Required<Customer.bAccountID>>>>
.Select(this, payment.CustomerId).FirstOrDefault();
//Todo: add assertion that will assert payment is made to only matching company payment.CompanyId
//Todo: find out if we need to handel Bank Account Types differently payment.BankAccountType
DateTime.TryParse(payment.Date, out var payDate);
return new CtpPayment
{
CustomerID = int.Parse(payment.CustomerId),
Customer = $"{customer.AcctCD}:{customer.AcctName}",
Amount = payment.Amount,
Description = $"Payment:{payment.Id}",
Id = payment.Id,
ApsTransactionID = payment.ApsTransactionId,
Currency = payment.Currency,
PaymentDate = payDate,
Invoices = InvoicesAsString(payment)
};
}
private static string InvoicesAsString(PaymentViewModel payment)
{
var Invoices = payment.Invoices.Select(x => x.InvoiceId);
StringBuilder stringBuilder = new StringBuilder();
foreach (string inv in Invoices)
{
stringBuilder.AppendFormat("{0} ", inv);
}
string result = stringBuilder.ToString();
if (result.Length > 100) result = result.Substring(0, 96) + "...";
return result;
}
private CtpAcumatica _ctpAcumatica;
public CtpAcumatica CtpAcumatica
{
get
{
if (_ctpAcumatica == null)
{
var graph = PXGraph.CreateInstance<PXGraph>();
_ctpAcumatica = new CtpAcumatica(setup.Current.CtpUrl,
setup.Current.CtpApiKey,
"NoLongerNeeded", //todo: refactor this out.
"NoLongerNeeded", //todo: refactor this out.
graph);
}
return _ctpAcumatica;
}
}
public CtpPaymentProcess()
{
Payments.SetProcessCaption("Process Payments");
Payments.SetProcessAllCaption("Process All Payments");
Payments.SetProcessDelegate<CtpPaymentProcess>(
delegate (CtpPaymentProcess graph, CtpPayment payment)
{
graph.Clear();
graph.ProcessPayment(payment, true);
}
);
//Alternate attempt proved un-successful
//Payments.SetProcessDelegate(PaymentGenerationDelegate);
}
/* implemented as a test. will remove from production code
private void PaymentGenerationDelegate(List<CtpPayment> list)
{
foreach (var payment in list)
{
ProcessPayment(payment, true);
}
}
*/
private void ProcessPayment(CtpPayment payment, bool massProcess)
{
PXTrace.WriteInformation($"Processing {payment}");
//for now we will only write to the trace window.
//Stopwatch stopWatch = new Stopwatch();
//stopWatch.Start();
//createPayment(payment);
//stopWatch.Stop();
//PXTrace.WriteInformation($"Payment {payment.ApsTransactionID} finished in {stopWatch.Elapsed.TotalSeconds} Seconds");
}
//todo: unfinished
private void createPayment(CtpPayment paymentData)
{
var paymentFromCtp = CtpAcumatica.GetPaymentRecord(long.Parse(paymentData.Id));
ARPaymentEntry arPaymentEntry = PXGraph.CreateInstance<ARPaymentEntry>();
ARPayment payment = new ARPayment
{
CustomerID = int.Parse(paymentFromCtp.CustomerId),
CuryOrigDocAmt = paymentData.Amount
};
arPaymentEntry.CurrentDocument.Insert(payment);
foreach (var invoice in paymentFromCtp.Invoices)
{
ARAdjust adj = new ARAdjust
{
AdjdRefNbr = invoice.InvoiceId,
CuryAdjgAmt = invoice.Amount
};
arPaymentEntry.Adjustments.Insert(adj);
}
arPaymentEntry.Persist();
PXTrace.WriteInformation(arPaymentEntry.ToString());
}
}
//This is the DAC definition.
[Serializable]
[PXPrimaryGraph(typeof(CtpPaymentProcess))]
//[PXNonInstantiatedExtension] this looked close
//to what we are looking for but experimenting
//with it did not yield desired results.
public class CtpPayment : IBqlTable
{
#region Selected
public abstract class selected : IBqlField{ }
[PXBool]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
public abstract class id : IBqlField { }
//todo: find out what size we need 50 is just a guess.
//[PXString(50, IsKey = true)] //We are able to get this to work only if
//we have at least one persisting field.
//we can live with this but would prefer to
//have the whole class as non-persistent
[PXString(50,IsKey = true)] //having only non persisting attributes will result in a
//Incorrect syntax near the keyword 'FROM'. error.
[PXUIField(DisplayName = "Click To Pay Id")]
public virtual string Id { get; set; }
public abstract class customer : IBqlField { }
[PXString(100)]
[PXUIField(DisplayName = "Customer")]
public virtual string Customer { get; set; }
public abstract class description : IBqlField {}
[PXString(200)]
[PXUIField(DisplayName = "Payment Description")]
public virtual string Description { get; set; }
public abstract class amount : IBqlField { }
[PXDecimal(2)]
[PXUIField(DisplayName = "Payment Amount")]
public virtual decimal? Amount { get; set; }
public abstract class customerId : IBqlField { }
[PXInt]
[PXUIField(DisplayName = "Customer ID")]
//todo: decorate this with the needed attributes to display friendly key instead of int.
public virtual int? CustomerID { get; set; }
public abstract class apsTransactionID : IBqlField { }
[PXString]
[PXUIField(DisplayName = "Transaction ID")]
public virtual string ApsTransactionID { get; set; }
public abstract class currency : IBqlField { }
[PXString(10)]//todo: determine best size. 10 is a guess.
[PXUIField(DisplayName = "Currency")]
public virtual string Currency { get; set; }
public abstract class paymentDate : IBqlField { }
[PXDate]
[PXUIField(DisplayName = "Payment Date")]
public virtual DateTime? PaymentDate { get; set; }
public abstract class invoices : IBqlField { }
[PXString(100)]
[PXUIField(DisplayName = "Invoices")]
public virtual string Invoices { get; set; }
}
Thanks, HB_Acumatica for the direction on this.
Changing my code to use the following got to the end result I needed. I Hope this helps someone in the future.
//old implementation that would not render any result when the process buttons where clicked.
//public IEnumerable payments()
//{
// paymentsFromCtpServer = CtpAcumatica.CheckForAllNewPayments(100);
// PXTrace.WriteInformation("Processing " + (paymentsFromCtpServer.Payments.Count) + " paymentsFromCtpServer");
// if (paymentsFromCtpServer.Payments != null)
// {
// // Loop processing each payment returned from the gateway, storing the
// // information into non persisted cache.
// foreach (var payment in paymentsFromCtpServer.Payments)
// {
// if (!payment.IsMarkedRetrieved)
// {
// yield return BuildCtpPayment(payment);
// }
// }
// }
//}
public IEnumerable payments()
{
paymentsFromCtpServer = CtpAcumatica.CheckForAllNewPayments(100);
PXCache cache = Caches[typeof(CtpPayment)];
cache.AllowInsert = false;
cache.AllowUpdate = false;
if (cache.Current == null)
{
foreach (var payment in paymentsFromCtpServer.Payments)
{
if (!payment.IsMarkedRetrieved)
{
cache.SetStatus(BuildCtpPayment(payment), PXEntryStatus.Held);
}
}
}
return Payments.Cache.Cached;
}

How to use Firebase Query for data with anonymous keys

I have the following database data which I intend to display on a ListView with FirebaseListAdapter
My problem is creating a Query since the child elements after date are anonymous. Here is the query code
Query query = FirebaseDatabase.getInstance().getReference().child("Updates").child(refMail).child(day)
.orderByKey();
refMail and day are user email address and date respectively.
Here is also my Data Model Class
public class NotesDataModel {
private String Note;
private String uid;
private String time;
public NotesDataModel(){
}
public NotesDataModel(String Note, String uid, String time){
this.Note=Note;
this.uid=uid;
this.time=time;
}
public String getNote() {
return Note;
}
public void setNote(String note) {
Note = note;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}}
and finally the adapter initialization
FirebaseListOptions<NotesDataModel> options = new FirebaseListOptions.Builder<NotesDataModel>()
.setQuery(query, NotesDataModel.class)
.setLayout(R.layout.notes_cell_layout)
.build();
mAdapter = new FirebaseListAdapter<NotesDataModel>(options) {
#Override
protected void populateView(View view, NotesDataModel note, int position) { //some code }}; notesList.setAdapter(mAdapter);
Previous version worked like this
ref = FirebaseDatabase.getInstance().getReferenceFromUrl(FactoryDaftari.firebaseURL + "Updates/" + refMail + "/" + day);
And the Adapter initialization
mAdapter = new FirebaseListAdapter<NotesDataModel>(this, NotesDataModel.class, R.layout.notes_cell_layout, ref) {
#Override
protected void populateView(View view, NotesDataModel note, int position) { }};
You won't be able to make this query with the way your data is structured. It's common in NoSQL databases to make copies of data, structured for the purpose of specialized querying. So, if you want to query a list of notes, you'll need a structure where all the notes are children of the same parent, then make your query against that structure.
(Also, organizing your notes by a node with a date, like you have now, may not even be the best general structure in the first place.)

Depending on Data on Firebase - build buttons including Images and Data

I'm quite new to programming and was looking quite a while now for a solution - but as I am not sure what exactly I am looking for, I decided to ask you.
Depending on the Data on Firebase I was looking to build a button including text and an image.
So for example I have a Database including:
User
Max (with the fields: University, Age, City)
Lena (with the fields: University, Age, City)
Is it possible to build a button with this Data but only if the Users are in the Database? So as there are 2 users - build 2 buttons including all the text (University, Age, City), if there would be 3 users - build 3 buttons.
Edit: Using Android Studio
I would recommend using recycler view and implementing onClick for recycler view.
This would take a lot of code:
Create xml for each item of recycler view
recycler_view_item.xml
Add recycler view to xml of current activity
3.Create a class MyUser.java like below:
public class MyUser {
private String University, City, Age;
public User(){}
public User(String University, String City) {
this.University = University;
this.City = City;
this.Age = Age;
}
public String getUniversity() { return University;}
public void setUniversity(String University) {
this.University = University;
}
public String getCity() {
return City;
}
public void setCity(String City) {
this.City = City;
}
public String getAge() {
return Age;
}
public void setAge(String Age) {
this.Age = Age;
}
}
Create adapter and view holder class
5.get user details from database in current activity :
private List<Book> userList;
userList = new ArrayList<>();
mRef = database.getReference().child("users");
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> bookData = dataSnapshot.getChildren();
for(DataSnapshot d : bookData){
MyUser myUser = d.getValue(User.class);
userList.add(myUser);
mAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Initialise the adapter with context and the userList
mAdapter = new MyRecyclerAdapter(getContext(), userList);
I have left out a lot of things like the adapter and view holder.
comment if u are stuck

Create a log everytime When methods in an interface class are called

I want to update a log file(txt) everytime when methods in a an interface class are called?
Is there any way to do this other than writing code in every method to create log?
Here's my 30 mins. you'll have to implement the logging code somewhere so you have to create another abstraction for your code. thus an abstract class is needed. i think. this is very quick and dirty.
public interface IService<T>
{
List<T> GetAll();
bool Add(T obj);
}
then you'll need the abstract class where you'll need to implement your logging routine
public abstract class Service<T> : IService<T>
{
private void log()
{
/// TODO : do log routine here
}
public bool Add(T obj)
{
try
{
log();
return AddWithLogging(obj);
}
finally
{
log();
}
}
public List<T> GetAll()
{
try
{
log();
return GetAllWithLog();
}
finally
{
log();
}
}
protected abstract List<T> GetAllWithLog();
protected abstract bool AddWithLogging(T obj);
}
as for your concrete classes
public class EmployeeService : Service<Employee>
{
protected override List<Employee> GetAllWithLog()
{
return new List<Employee>() { new Employee() { Id = 0, Name = "test" } };
}
protected override bool AddWithLogging(Employee obj)
{
/// TODO : do add logic here
return true;
}
}
public class CompanyService : Service<Company>
{
protected override List<Company> GetAllWithLog()
{
return new List<Company>() { new Company() { Id = 0, Name = "test" } };
}
protected override bool AddWithLogging(Company obj)
{
/// TODO : do add logic here
return true;
}
}
public class Employee
{
public int Id {get;set;}
public string Name { get; set;}
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
then on your implementation you can just..
static void Main(string[] args)
{
IService<Employee> employee = new EmployeeService();
List<Employee> employees = employee.GetAll();
foreach (var item in employees)
{
Console.WriteLine(item.Name);
}
IService<Company> company = new CompanyService();
List<Company> companies = company.GetAll();
foreach (var item in companies)
{
Console.WriteLine(item.Name);
}
Console.ReadLine();
}
hope this helps!
I think you would have to use Aspect Oriented Programming to achieve that. Read http://www.sharpcrafters.com/aop.net
I think you meant class (instead of interface)
Two options I can think of:
Implementing INotifyPropertyChanged which is in lines of writing code in every method
or
to adopt on of the AOP frameworks in the article http://www.codeproject.com/KB/cs/AOP_Frameworks_Rating.aspx if that is not a major leap

Resources