I've been trying to cancel a Sales order packing slip. I'm verifying if it worked by trying to repost but receiving one error after the next.
I have found a way to post a packing slip but is there an easy way to cancel a packing slip without finding all the fields that need to be updated in the inventory movement tables?
Is there something simple like posting (example below):
static void SalesOrderPost(Args _args)
{
SalesFormLetter salesFormLetter;
salesTable salesTable;
salesTable = SalesTable::find('SO-101248');
salesFormLetter = SalesFormLetter::construct(
DocumentStatus::PackingSlip);
salesFormLetter.update(
salesTable,
systemDateGet(),
SalesUpdate::All,
AccountOrder::None,
NoYes::No,
NoYes::Yes);
}
I was able to retrieve the customer packing slip journal record and pass it to the SalesFormLetter_PackingSlipCancel action menu item.
CustPackingSlipJour custPackingSlipJour;
boolean isCancelEnabled, isCorrectionEnabled;
Args args;
//find latest packing slip
select * from custPackingSlipJour
order by PackingSlipId desc
where custPackingSlipJour.SalesId == salesTable.SalesId;
[isCancelEnabled, isCorrectionEnabled] = custPackingSlipJour.canPackingSlipBeCanceledOrCorrected();
if(isCancelEnabled)
{
//"cancel" latest packing slip
args = new Args();
args.record(custPackingSlipJour);
new MenuFunction(menuitemActionStr(SalesFormLetter_PackingSlipCancel), MenuItemType::Action).run(args);
}
super();
Related
For sample I have one order that my user can add one store and in each store a lot of itens:
Amazon
- cup - $ 1
- notebook - $ 3
- $ 4 Ebay
- bike - $ 10
- boat - $ 13
- $ 23
Total order: $ 27 [Button to send the order]
And in my project I have 3 components:
CartView - (show the total from order and a button)
- StoreView (show de Store name, and total)
---StoreitemView (show the item and the button to remove)
lets to the doubts:
1 - The best way to show thats lists are usingo a GRID with one ROW? some like this:
Grid<StoreView> myGrid = new Grid();
myGrid.addComponentColumn(this::createStoreView).setAutoWidth(true);
or Its best to use a for just like this:
Div myDiv = new Div();
for(Store store in StoreList){
muDiv.add(new StoreView(store);
}
2 - How can I pass event to parent? so when my user click a button at StoreItemView I need to emit that event to my CartView(passing to StorView, and go to CarView to update the values and recreate the cart)
tks
Layout
The layout depends on how many stores and items you expect. If the number is low, just looping through and adding components is a decent approach.
If you have many items, using a Grid with one column is a better approach, as all items aren't rendered at once. An even better approach might be the IronList, or since Vaadin 21 the VirtualList.
If your views are complex with a lot of components, it's a good idea to use a TemplateRenderer instead of a ComponentRenderer. If writing views in HTML instead of Java is not your cup of tea, you can keep on using the ComponentRenderer, especially if performance seems to be good.
If there are a lot of items per store, you can consider having a virtual list for the store items inside the store also. Especially if there are only a few stores.
Events
There is no correct answer here. It seems like your StoreView and StoreItemView are tightly coupled, so the communication can be tightly coupled too. For example, the StoreItemView can expose the button directly with a getRemoveButton() method.
I would use the ComponentEvent for the removal event, something like the code below. Your logic for how the StoreItemViews are created would be different, and you could add a method in the StoreView for adding the event listener. You might want to add some data to the event, too.
public class StoreView extends HorizontalLayout {
public StoreView() {
// Create your store items as you see fit
StoreItemView storeItemView = new StoreItemView();
storeItemView.getRemoveButton().addClickListener(e -> {
remove(storeItemView);
fireEvent(new StoreItemRemovedEvent(storeItemView));
});
add(storeItemView);
}
public static class StoreItemRemovedEvent extends
ComponentEvent<StoreItemView> {
public StoreItemRemovedEvent(StoreItemView source) {
super(source, false);
}
}
}
public class CartView extends VerticalLayout {
public CartView() {
StoreView storeView = new StoreView();
ComponentUtil.addListener(storeView, StoreView.StoreItemRemovedEvent.class, e ->
Notification.show("Store item removed"));
add(storeView);
}
}
Can anyone tell me how to update the keyword status,keyword text and keyword maxCpc using google adwords api.I am trying the basic example i.e Update keyword but it is not working.
Please let me know the procedure to solve this problem !
I don't know which language do you use, but I've used this C# code to modify keywords states through Google AdWords API:
public void SetKeywordState(long groupId, long keywordId, bool newState)
{
// Make sure your web.config contains correct data (developer token etc.)
AdWordsUser user = new AdWordsUser();
// 1st step - creation of criterion service.
var criterionService = (AdGroupCriterionService)user
.GetService(Google.Api.Ads.AdWords.Lib.AdWordsService
.v201406.AdGroupCriterionService);
// 2nd step - creation of AdGroupCriterion (keyword is criterion)
// and new state assignment
var tgtKwrd = new BiddableAdGroupCriterion
{
adGroupId = groupId,
criterion = new Keyword { id = keywordId },
userStatus = newState ? UserStatus.ENABLED : UserStatus.PAUSED
};
// 3rd step - creation of operation
var co = new AdGroupCriterionOperation
{
#operator = Operator.SET,
operand = tgtKwrd
};
// 4th step - commit keyword changes to Google.
criterionService.mutate(new[] { co });
}
Modification of maxCPC and keywordText is going exactly in the same way.
Also, there are many useful code examples in different languages. In this case I've used this code example from Google libraries.
Hope this helps.
My Client Center -> Select your campaign -> Go to the keywords Tab -> Make changes as needed.
OPTIONAL: try using the AdWords Editor. It is freely available for download. Though I wouldn't really recommend this as its for advanced users.
1) http://www.google.com/intl/en/adwordseditor/
I am trying to use the Remarketing feature for the first time. I have got the Remarketing code from Adwords and placed it on the website.
Looking through the examples; i have garnered the below flow.
With #2 i can associate one of my Userlist with a predefined Adgroup to be shown during Remarketing. My question is how do i link the tracker ID that i have received (looks like var google_conversion_id = 9925XXXXX) with the code below? where is this linking done? UserListConversionTypes and BasicUserList both have ID's; am i supposed to set any of those or this is done automatically?
Any pointers/help will be appreciated.
Please also let me know if you fine any issue with the code below.
set up remarketing using the AdWords API in two steps:
Create a remarketing list.
Create a CriterionUserList to tie your list to an AdGroup.
1.Create a remarketing list
Creating a remarketing list involves the creation of two separate entities: the RemarketingList itself and its associated UserListConversionTypes also known as remarketing tags.
The following code shows how to create a remarketing list.
AdWordsServices adWordsServices, AdWordsSession session) throws Exception {
// Get the UserListService.
AdwordsUserListServiceInterface userListService =
adWordsServices.get(session, AdwordsUserListServiceInterface.class);
// Get the ConversionTrackerService.
ConversionTrackerServiceInterface conversionTrackerService =
adWordsServices.get(session, ConversionTrackerServiceInterface.class);
UserListConversionType conversionType = new UserListConversionType();
conversionType.setName("Mars cruise customers #" + System.currentTimeMillis());
// Create remarketing user list.
RemarketingUserList userList = new RemarketingUserList();
userList.setName("Mars cruise customers #" + System.currentTimeMillis());
userList.setDescription("A list of mars cruise customers in the last year");
userList.setMembershipLifeSpan(365L);
userList.setConversionTypes(new UserListConversionType[] {conversionType});
// Create operations.
UserListOperation operation = new UserListOperation();
operation.setOperand(userList);
operation.setOperator(Operator.ADD);
UserListOperation[] operations = new UserListOperation[] {operation};
// Add user list.
userList = userListService.mutate(operations).getValue()[0];
2.Tie a remarketing list to an AdGroup
A new type of criteria object called CriterionUserList is now part of v201008. Through this type of criteria you are able to tie a UserList to an AdGroup. As with other types of
criteria, this type is also managed through the AdGroupCriterionService. The following code shows you how to create a CriterionUserList and tie it to an existing AdGroup.
// Create user list criterion.
CriterionUserList userListCriterion = new CriterionUserList();
userListCriterion.setUserListId(userListId);
// Create biddable ad group criterion.
BiddableAdGroupCriterion biddableCriterion = new BiddableAdGroupCriterion();
biddableCriterion.setAdGroupId(adGroupId);
biddableCriterion.setCriterion(userListCriterion);
// Create operation.
AdGroupCriterionOperation operation = new AdGroupCriterionOperation();
operation.setOperand(biddableCriterion);
operation.setOperator(Operator.ADD);
AdGroupCriterionOperation[] operations = new AdGroupCriterionOperation[] {operation};
// Add keywords.
AdGroupCriterionReturnValue result = adGroupCriterionService.mutate(operations);
Thanks,
-Devraj
Those two examples from Google pretty much cover how it's set up
The linking is done behind the scenes by Google - they match the ID in YOUR remarketing tag (which is usually specific to one AdWords account) with your remarketing lists (which are again at account level).
You can have many remarketing lists with varying criteria (visited certain URLs on your site, converted, etc. & combinations thereof) and link one of those lists to your campaign or adgroup.
I'd maybe suggest doing this through the AdWords web user interface first time so you understand the process you are automating with the API
You can get all existing conversion trackers as below.
ConversionTracker theConversionTracker = null;
Selector conversionTrackerSelector = new Selector();
conversionTrackerSelector.fields = new string[] { "Id", "Name" };
ConversionTrackerPage conversionTrackerPage = new ConversionTrackerPage();
try
{
ConversionTrackerService conversionTrackerService = (ConversionTrackerService)adWordsUser.GetService(AdWordsService.v201502.ConversionTrackerService);
conversionTrackerPage = conversionTrackerService.get(conversionTrackerSelector);
if (conversionTrackerPage != null && conversionTrackerPage.entries != null && conversionTrackerPage.entries.Length > 0)
{
//iterate over conversionTrackerPage.entries and write down the Id of the convertion tracker you need
}
}
catch (Exception ex)
{
}
Then you can use the Id when creating the conversion type
UserListConversionType conversionType = new UserListConversionType();
conversionType.name = "My conversion type name";
conversionType.id = 19XXXXXXXXL; // The Id you wrote down.
So this is what I ended up with to get realtime starring/liking (of communities, in my case) working, with a Firebase datastore. It's a mess and surely I'm missing some fundamentals.
Here my element gets communities, each as a Map community stored in an observed List communities. It has to rewrite that List several times as it changes each community Map based on the results of the changed star count and the user's starred state, and some other fun:
getCommunities() {
// Since we call this method a second time after user
// signed in, clear the communities list before we recreate it.
if (communities.length > 0) { communities.clear(); }
var firebaseRoot = new db.Firebase(firebaseLocation);
var communityRef = firebaseRoot.child('/communities');
// TODO: Undo the limit of 20; https://github.com/firebase/firebase-dart/issues/8
communityRef.limit(20).onChildAdded.listen((e) {
var community = e.snapshot.val();
// snapshot.name is Firebase's ID, i.e. "the name of the Firebase location",
// so we'll add that to our local item list.
community['id'] = e.snapshot.name();
print(community['id']);
// If the user is signed in, see if they've starred this community.
if (app.user != null) {
firebaseRoot.child('/users/' + app.user.username + '/communities/' + community['id']).onValue.listen((e) {
if (e.snapshot.val() == null) {
community['userStarred'] = false;
// TODO: Add community star_count?!
} else {
community['userStarred'] = true;
}
print("${community['userStarred']}, star count: ${community['star_count']}");
// Replace the community in the observed list w/ our updated copy.
communities
..removeWhere((oldItem) => oldItem['alias'] == community['alias'])
..add(community)
..sort((m1, m2) => m1["updatedDate"].compareTo(m2["updatedDate"]));
communities = toObservable(communities.reversed.toList());
});
}
// If no updated date, use the created date.
if (community['updatedDate'] == null) {
community['updatedDate'] = community['createdDate'];
}
// Handle the case where no star count yet.
if (community['star_count'] == null) {
community['star_count'] = 0;
}
// The live-date-time element needs parsed dates.
community['updatedDate'] = DateTime.parse(community['updatedDate']);
community['createdDate'] = DateTime.parse(community['createdDate']);
// Listen for realtime changes to the star count.
communityRef.child(community['alias'] + '/star_count').onValue.listen((e) {
int newCount = e.snapshot.val();
community['star_count'] = newCount;
// Replace the community in the observed list w/ our updated copy.
// TODO: Re-writing the list each time is ridiculous!
communities
..removeWhere((oldItem) => oldItem['alias'] == community['alias'])
..add(community)
..sort((m1, m2) => m1["updatedDate"].compareTo(m2["updatedDate"]));
communities = toObservable(communities.reversed.toList());
});
// Insert each new community into the list.
communities.add(community);
// Sort the list by the item's updatedDate, then reverse it.
communities.sort((m1, m2) => m1["updatedDate"].compareTo(m2["updatedDate"]));
communities = toObservable(communities.reversed.toList());
});
}
Here we toggle the star, which again replaces the observed communities List a few times as we update the count in the affected community Maps and thus rewrite the List to reflect that:
toggleStar(Event e, var detail, Element target) {
// Don't fire the core-item's on-click, just the icon's.
e.stopPropagation();
if (app.user == null) {
app.showMessage("Kindly sign in first.", "important");
return;
}
bool isStarred = (target.classes.contains("selected"));
var community = communities.firstWhere((i) => i['id'] == target.dataset['id']);
var firebaseRoot = new db.Firebase(firebaseLocation);
var starredCommunityRef = firebaseRoot.child('/users/' + app.user.username + '/communities/' + community['id']);
var communityRef = firebaseRoot.child('/communities/' + community['id']);
if (isStarred) {
// If it's starred, time to unstar it.
community['userStarred'] = false;
starredCommunityRef.remove();
// Update the star count.
communityRef.child('/star_count').transaction((currentCount) {
if (currentCount == null || currentCount == 0) {
community['star_count'] = 0;
return 0;
} else {
community['star_count'] = currentCount - 1;
return currentCount - 1;
}
});
// Update the list of users who starred.
communityRef.child('/star_users/' + app.user.username).remove();
} else {
// If it's not starred, time to star it.
community['userStarred'] = true;
starredCommunityRef.set(true);
// Update the star count.
communityRef.child('/star_count').transaction((currentCount) {
if (currentCount == null || currentCount == 0) {
community['star_count'] = 1;
return 1;
} else {
community['star_count'] = currentCount + 1;
return currentCount + 1;
}
});
// Update the list of users who starred.
communityRef.child('/star_users/' + app.user.username).set(true);
}
// Replace the community in the observed list w/ our updated copy.
communities.removeWhere((oldItem) => oldItem['alias'] == community['alias']);
communities.add(community);
communities.sort((m1, m2) => m1["updatedDate"].compareTo(m2["updatedDate"]));
communities = toObservable(communities.reversed.toList());
print(communities);
}
There's also some other craziness where we have to get the list of communities again when app.changes because we only load app.user after the app and list initially load, and now that we have the user we need to turn on the appropriate stars. So my attached() looks like:
attached() {
app.pageTitle = "Communities";
getCommunities();
app.changes.listen((List<ChangeRecord> records) {
if (app.user != null) {
getCommunities();
}
});
}
There, it seems I could just be getting the stars and updating said each affected community Map, then repopulating the observed communities List, but that's the least of it.
The full thing: https://gist.github.com/DaveNotik/5ccdc9e74429cf87d641
How can I improve all this Map/List management, e.g. where every time I change a community Map, I have to rewrite the whole communities List? Should I be thinking of it differently?
What about all this querying Firebase? Surely, there's a better way, but it seems I need to do a lot to keep it realtime, and also the element gets attached and detached, so it seems I need to run getCommunities() each time. Unless the OOP way is objects get created, and they're always there to be observed whenever the element is attached? I'm missing those fundamentals.
This app.changes business to handle the case where we load the list before we have the app.user (which then means we want to load her stars) - is there a better way?
Other ridiculousness?
Big question, I know. Thank you for helping me get a handle on the right approach as I move forward!
I think there is two different ways to choose, if you want to keep a data of your application in real time sync with server database:
1 Polling (pull method ie. a client pulls the data from server)
Application polls ie. requests the updated data from the server. Polling can be automatic (for example with interval of 60s) or requested by user (= refresh). The short automatic interval will cause high load on server and with long interval you lose real time feeling.
2 Full-duplex (push method ie. server can push the data to the client)
An application and a server have full-duplex connection in between and server is able to send the data or a notification of the data available to the client. Then the client can decide whether or not to retrieve the data.
This method is a modern one, because it'll keep the net traffic and the server load in minimum and yet providing a real time updates.
The firebase boasts with this kind of updates, but I'm not sure is it full-dublex or just a clever way of polling. Websocket protocol is a real full-duplex connection and dart server supports it.
The updated data from a server can include:
1 A full dataset
Basically the server sends a full dataset (=initial query) and the server doesn't "know" anything about updated data. This is easiest way to go, if you have reasonable small datasets. Many times you'll have a very small datasets among the big ones, so this way can be useful.
2 A dataset including a new data only
The server can send a dataset based on modified timestamp ie. every time a record in the database changes, a timestamp for update will be saved and the query can be filtered based on this timestamp. In other words application knows when it has last updated the data and then requests newer data.
3 A changed record
A server keeps a track of updated data and sends it to the application. The data can be sent record by record when changes occurs or server can collect the data for a bigger chunks to be sent. This method requires a server to keep a track of every client connected in order to send a correct data to each client. When you add an authentication process for clients ie. not every data can be send to all, it can get quite complicated.
I think the easiest way is to use the method number 2 for updated data.
Last thing...
What to do with the data received?
1 Handle everything as a new
If application receives an updated data, it will destroy/clear all the lists and maps and recreate/refill them with the new data. Typical problems with this are a user loses a current position on a page or the data user were looking jumps around. If application has modified or extended an old data for some reason, all those modifications will be lost. This method works ok, if a user requests a refresh.
2 Update only the changed data
The application never clears initial list or maps, it just updates them with a new received data. Typically you will construct a new combined map from queried data for your specific need (for example a certain view). The combined map has already all information you want to show in the specific view (default values even if the initial queries didn't had the data for the field) and you just update a new values in it.
If the updated information needs a new member in the list you just add it in the end.
If the updated information requires a deletion from the list, it might be a good thing to use extra field "active" and filter the list/map with it. With filtering you won't lose any referencies or so.
If you need to sort a data or filter it, it should be done by a view or user request. Basically the data is stored in the application and updated as needed. When a user needs to see the data in a specific way, the view should show the data a proper way. This is called model-controller-view and the main idea is to separate the data from the view.
I'm sorry this long answer didn't answer any of your questions, but I tried to cut this challenge to a smaller chunks. Many times you can see an interface between these chunks and you can design and organize your code nicely by using these interfaces.
edit #2: Question solved halfways. Look below
As a follow-up question, does anyone know of a non-intrusive way to solve what i'm trying to do below (namely, linking objects to each other without triggering infinite loops)?
I try to create a asp.net-mvc web application, and get a StackOverFlowException. A controller triggers the following command:
public ActionResult ShowCountry(int id)
{
Country country = _gameService.GetCountry(id);
return View(country);
}
The GameService handles it like this (WithCountryId is an extension):
public Country GetCountry(int id)
{
return _gameRepository.GetCountries().WithCountryId(id).SingleOrDefault();
}
The GameRepository handles it like this:
public IQueryable<Country> GetCountries()
{
var countries = from c in _db.Countries
select new Country
{
Id = c.Id,
Name = c.Name,
ShortDescription = c.ShortDescription,
FlagImage = c.FlagImage,
Game = GetGames().Where(g => g.Id == c.GameId).SingleOrDefault(),
SubRegion = GetSubRegions().Where(sr => sr.Id == c.SubRegionId).SingleOrDefault(),
};
return countries;
}
The GetGames() method causes the StackOverflowException:
public IQueryable<Game> GetGames()
{
var games = from g in _db.Games
select new Game
{
Id = g.Id,
Name = g.Name
};
return games;
}
My Business objects are different from the linq2sql classes, that's why I fill them with a select new.
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
edit #1: I have found the culprit, it's the following method, it triggers the GetCountries() method which in return triggers the GetSubRegions() again, ad nauseam:
public IQueryable<SubRegion> GetSubRegions()
{
return from sr in _db.SubRegions
select new SubRegion
{
Id = sr.Id,
Name = sr.Name,
ShortDescription = sr.ShortDescription,
Game = GetGames().Where(g => g.Id == sr.GameId).SingleOrDefault(),
Region = GetRegions().Where(r => r.Id == sr.RegionId).SingleOrDefault(),
Countries = new LazyList<Country>(GetCountries().Where(c => c.SubRegion.Id == sr.Id))
};
}
Might have to think of something else here :) That's what happens when you think in an OO mindset because of too much coffee
Hai! I think your models are recursively calling a method unintentionally, which results in the stack overflow. Like, for instance, your Subregion object is trying to get Country objects, which in turn have to get Subregions.
Anyhow, it always helps to check the stack in a StackOverflow exception. If you see a property being accessed over and over, its most likely because you're doing something like this:
public object MyProperty { set { MyProperty = value; }}
Its easier to spot situations like yours, where method A calls method B which calls method A, because you can see the same methods showing up two or more times in the call stack.
The problem might be this: countries have subregions and subregions have countries. I don't know how you implement the lazy list, but that might keep calling GetCountries and then GetSubRegions and so on. To find that out, I would launch the debugger en set breakpoints on the GetCountries and GetSubRegions method headers.
I tried similar patterns with LinqToSql, but it's hard to make bidirectional navigation work without affecting the performance to much. That's one of the reasons I'm using NHibernate right now.
To answer your edited question, namely: "linking objects to each other without triggering infinite loops":
Assuming you've got some sort of relation where both sides need to know about the other... get hold of all the relevant entities in both sides, then link them together, rather than trying to make the fetch of one side automatically fetch the other. Or just make one side fetch the other, and then fix up the remaining one. So in your case, the options would be:
Option 1:
Fetch all countries (leaving Subregions blank)
Fetch all Subregions (leaving Countries blank)
For each Subregion, look through the list of Countries and add the Subregion to the Country and the Country to the Subregion
Option 2:
Fetch all countries (leaving Subregions blank)
Fetch all Subregions, setting Subregion.Countries via the countries list fetched above
For each subregion, go through all its countries and add it to that country
(Or reverse country and subregion)
They're basically equialent answers, it just changes when you do some of the linking.