Updating fields from changes in scroll levels - peoplesoft

I have a page that has 3 levels. Levels 0 & 1 are from the same record. Level 2 is from a second record.
When a change is made to level 1, I would like to apply that change to the same field in Level 2's record.
Basically, this deals with EFF_STATUS in peoplesoft. If an effective row gets added to the record, and the EFF_STATUS is changed to Active or Inactive, I'd like to update the EFF_STATUS in my second record to match.
Here is the code I'm trying to execute and it is giving me an error of.. "Invalid row number 2 for class Rowset method GetRow. (2,263) K_OFFNSV_REC_EX.EFF_STATUS.SaveEdit PCPC:267 Statement:8 "
If %Component = Component.K_OFFNSV_CMP Then
Local Rowset &LEVEL0, &Level1, &Level2;
Local Row &L1Row, &L2Row;
Local number &I, &J;
&LEVEL0 = GetLevel0();
&Level1 = &LEVEL0(1).GetRowset(Scroll.K_OFFNSV_REC);
&I = CurrentRowNumber();
&L1Row = &Level1(&I);
If &L1Row.IsNew Then
&L1Row.K_OFFNSV_REC.LASTUPDDTTM.Value = %Date;
&L1Row.K_OFFNSV_REC.OPRID.Value = %UserId;
End-If;
&Level2 = &L1Row.GetRowset(Scroll.K_OFFNSV_REC_EX);
For &J = 1 To &Level2.ActiveRowCount
&L2Row = &Level2(&J);
&L2Row.K_OFFNSV_REC_EX.EFFDT.Value = %Date;
&L2Row.K_OFFNSV_REC_EX.EFF_STATUS.Value = &L1Row.K_OFFNSV_REC.EFF_STATUS.Value;
End-For;
End-If;

A suggestion, change/set values on SavePreChange. SaveEdit should be use for validations only.
With that being said:
Your currentrownumber returns the current row, so probably it is returning the row #2 on the level #2.
You need CurrentRowNumber(1) to get the #1 level.
Also, why are you setting the EFFDT yourself on the save? Look at other peoplesoft pages, you will see it is populated on the add by PS itself.

Related

Does a OUTER-JOIN always divide the query in two parts, leaving the part on the right empty if not complete in Progress?

I'm trying to do an OUTER-JOIN in progress using this page as inspiration. My code is as follows
OPEN QUERY qMovto
FOR EACH movto-estoq
WHERE movto-estoq.lote BEGINS pc-lote
AND movto-estoq.it-codigo BEGINS pc-it-codigo
AND movto-estoq.dt-trans >= pd-data1
AND movto-estoq.dt-trans <= pd-data2
AND movto-estoq.cod-emitente = pi-cod-emitente,
EACH item OUTER-JOIN
WHERE movto-estoq.it-codigo = item.it-codigo,
EACH item-cli OUTER-JOIN
WHERE item-cli.item-do-cli BEGINS pc-item-cli
AND movto-estoq.cod-emitente = item-cli.cod-emitente
AND movto-estoq.it-codigo = item-cli.it-codigo
AND movto-estoq.un = item-cli.unid-med-cli,
EACH nota-fiscal OUTER-JOIN
WHERE movto-estoq.nro-docto = nota-fiscal.nr-nota-fis
BY movto-estoq.dt-trans DESCENDING BY movto-estoq.hr-trans DESCENDING.
The problem that is happening is when 1 element in null, all the other elements that are in the OUTER-JOIN are appearing as null as well, even though they are not null. Is there a better way to write this code? Should I put 'LEFT' before the OUTER-JOIN? Thanks for your time.
To make your example easier, consider making it work from ABL dojo. The following code:
define temp-table ttone
field ii as int
.
define temp-table tttwo
field ii as int
field cc as char
.
create ttone. ttone.ii = 1.
create ttone. ttone.ii = 2.
create tttwo. tttwo.ii = 2. tttwo.cc = "inner".
create tttwo. tttwo.ii = 3. tttwo.cc = "orphan".
define query q for ttone, tttwo.
open query q
for each ttone,
each tttwo outer-join where tttwo.ii = ttone.ii.
get first q.
do while available ttone:
message ttone.ii tttwo.cc.
get next q.
end.
Can be run from https://abldojo.services.progress.com/?shareId=600f40919585066c219797ed
As you can see, this results in :
1 ?
2 inner
The join which is not available is shown as unknown. The value of the outer part of the join is shown.
Since you do not show how you are getting an unknown value for everything, maybe you are concatenating the unknown values?

Update random row in DB using Flask-Sqlalchemy

I've been trying to update a randomly selected row in my Sqlite database using Flask and the Flask-Sqlalchemy. I have just a few rows in the database with columns called "word", "yes", and "no", where word is a string and yes and no are integers. There are two buttons on the "vote" view, yes and no. When a button is pressed, the appropriate code executes, should increment the yes or no column, and the view is updated with a new random word from the Word table.
#app.route("/vote", methods=["GET", "POST"])
def vote():
#Get random row from database
query = db.session.query(Word)
rowCount = int(query.count())
row = query.offset(int(rowCount*random.random())).first()
#POST
# If "yes" button is pressed, increment yes column in database
if request.method == "POST":
if request.form.get("yes"):
row.yes += 1
db.session.commit()
return render_template("vote.html", row=row)
# otherwise increment no column
elif request.form.get("no"):
row.no += 1
db.session.commit()
return redirect(url_for("vote"))
#GET
# on get request, render vote.html
return render_template("vote.html", row=row)
This code is working, but the yes and no columns are only updated when the view comes back around to the random word the next time. If I close the browser right after clicking a button, the database is not incremented. I think this has something to do with db.session.commit(), or something about the session. It seems like:
row.yes += 1
is saved in the session object, but only committed when that database row is queried the next time. This code DID work when I replaced the query at the top of the method with:
row = Word.query.get(4)
which returns the row with id of 4. With this query, the yes or no column are updated immediately.
Any thoughts?
Thanks
Thanks all. I figured out the problem. The database incrementing was actually working fine, but I wasn't incrementing the correct rows. The problem was that I generated a random row from the database on each call of the vote() method, which meant that I got a random value for the GET request, and a different random value for the POST request, and ended up incrementing that different random value in the POST request.
I separated the logic out into two methods for the "/vote" route, getWord() and vote(), and created a randRow() method for the row generation. I needed to store the random row that gets generated when getWord() is called, so I used session variables so I could access the random row from the vote() method. It's a bit verbose, but seems to work.
Anyone have a better idea about how to achieve this?
#app.route('/vote', methods=["GET"])
def getWord():
wordObj = randRow()
session['word'] = wordObj.word
session['yesVotes'] = wordObj.yes
session['noVotes'] = wordObj.no
return render_template("vote.html", word=session['word'], yesVotes=session['yesVotes'], noVotes=session['noVotes'])
#app.route('/vote', methods=["POST"])
def vote():
# store session 'word' in word variable
# look up word in database and store object in wordObj
word = session['word']
wordObj = Word.query.filter_by(word=word).first()
# check button press on vote view, increment yes or no column
# depending on which button was pressed
if request.form.get("yes"):
wordObj.yes = wordObj.yes + 1
elif request.form.get("no"):
wordObj.no = wordObj.no + 1
db.session.commit()
return redirect(url_for("getWord"))
###### HELPERS ######
# returns a random row from the database
def randRow():
rowId = Word.query.order_by(func.random()).first().id
row = Word.query.get(rowId)
return row
I think you need to add the update into the session before the commit, using code like this:
[...]
row.yes += 1
db.session.add(row)
db.session.commit()
[...]
That's the pattern that I use for a basic update in Flask-SQLAlchemy.

Combo Box Filter Based on Value in Hidden Form

After a successful logon information about the user is held in a always open but hidden form.
Within the program there are various dropdowns that I want to filter based on 'txt_security' from the hidden form.
Row Source Example
SELECT tbl_master_ship.master_ship_id, tbl_master_ship.admin_only
FROM tbl_master_ship;
Example of data is there are 5 total ships, only one is admin_only. If txt_security = 1 then show all 5 ships else hide the one record marked admin_only.
I tried this but it only shows the one record if txt_security = 1.
WHERE (((tbl_master_ship.admin_only)=IIf([forms]![frm_global_variables]![txt_security]=0,True,False)))
This should be the easiest way:
WHERE [Forms]![frm_global_variables]![txt_security] = 1
OR tbl_master_ship.admin_only = 0
Only if [txt_security] <> 1 AND admin_only = True will the record not be shown.

How to create add and subtract buttons to track inventory

I've been searching for similar solutions out there but am coming up short so far. Here is what I want to accomplish:
I need to come up with a basic solution to sync inventory quantities at the end of each day. We take physical counts of inventory sold throughout the day but need something to log these changes and share between users. I would like to utilize two buttons (click one to subtract amount of items sold at the end of the day and click one button to add newly received inventory).
This is how my sheet is set up:
Col A: Product Tag
Col B: Product sku
Col C: Amount Sold Today
Col D: Total Inventory Quantity
Col E: Add New Inventory
Column D will be pre-populated with initial inventory counts. At the end of each day, I would like to go down my product list and fill in the amount of each item sold that day in Column C. Once Column C is fully populated, I would like to click the "subtract" button and have Column C subtracted from Column D.
On the other side, once we receive new stock of an item I would like to enter these counts into Column E. Once this column is fully populated, I would like to click the "Add" button and have Column E added to Column D. Ideally once the add or subtract function has been completed, columns C or E will be cleared and ready for the next days entry.
I already have designed my buttons, I just need help coming up with the scripts to accomplish this.
You can use Google Apps Script for this.
If you are unfamiliar, in your particular spreadsheet, go to Tools → Script Editor and then select the Blank Project option.
Then you can write functions like this to achieve what you want!
function subtractSold() {
var sheet = SpreadsheetApp.getActiveSheet();
var c1 = sheet.getRange("C2");
var c2 = sheet.getRange("D2");
while (!c1.isBlank() && !c2.isBlank()){
c2.setValue(c2.getValue() - c1.getValue());
c1.clear();
c1 = c1.offset(1, 0);
c2 = c2.offset(1, 0);
}
}
Basically what the function does is:
Get a reference to the active spreadsheet
Get references to the cells C2 and D2, for the first row of data.
Use a while loop to repeated go through the rows. Terminate when either cell is empty.
In the loop, we get the appropriate values, subtract and set the value back into the cell. Then we clear the cell in column C. We then move both cell references down by one row (the offset method returns a reference to the original cell, but offset by row, column).
Then assign the script to the button image by entering the name of the function (subtractSold in this case) in the "Assign script" option for the button.
I have made an example sheet here (go to File → Make a Copy to try the scripts and see the code): https://docs.google.com/spreadsheets/d/1qIJdTvG0d7ttWAUEov23HY5aLhq5wgv9Tdzk531yhfU/edit?usp=sharing
A bit faster
If you try the sheet above you can see it processes one row at a time, which might get pretty slow when you have a lot of rows. It is probably faster to process the entire column in bulk, but it may be a bit more complicated to understand:
function subtractSoldBulk() {
var sheet = SpreadsheetApp.getActiveSheet();
var maxRows = sheet.getMaxRows();
var soldRange = sheet.getRange(2, 3, maxRows); // row, column, number of rows
var totalRange = sheet.getRange(2, 4, maxRows);
var soldValues = soldRange.getValues();
var totalValues = totalRange.getValues();
for (var row in soldValues) {
var soldCellData = soldValues[row][0];
var totalCellData = totalValues[row][0];
if (soldCellData != "" && totalCellData != "") {
totalValues[row][0] = totalCellData - soldCellData;
soldValues[row][0] = "";
}
}
soldRange.setValues(soldValues);
totalRange.setValues(totalValues);
}
The difference here is that instead of getting one cell, we get one range of cells. The getValues() method then gives us a 2D array of the data in that range. We do the calculations on the two arrays, update the data in the arrays, and then set the values of the ranges based on the array data.
You can find documentation for the methods used above from Google's documentation: https://developers.google.com/apps-script/reference/spreadsheet/sheet

Need help building a menuopt file for Jenzabar CX

I'm not sure if anyone out here uses Jenzabar & ACE reporting, but the question is specific to that as far as I know.
I'm building an ACE report and the menuopt file for it has to be modified to lookup values for a parameter based on several specific conditions.
The portion of the menuopt file I have now is:
LU7 = crs_rec.title1, optional;
PA7: optional,
comments = "Enter a course number - leave blank if for all"
default = "",
lookup LU7 joining *crs_rec.crs_no,
upshift,
length = 10;
I'm looking to modify the lookup so that it only lists courses that can be found by this SQL statement:
SELECT DISTINCT crs_no
FROM crs_rec
WHERE dept IN ( SELECT dept
FROM dept_table
WHERE div IN ('CCE','HLTH'));
If anyone is familiar with using Jenzabar CX & ACE reporting, any help would be appreciated.
Thanks
I got this answer from someone on a Jenzabar listserv....
Sometimes you can get the same effect by limiting it based on other params.
For example:
LU6 = cat_table.txt;
PA6: optional,
comments = "COMMENT_CAT_TBCODE",
lookup LU6 joining *cat_table.cat,
upshift,
length = 4;
LU7 = crs_rec.title1, optional;
LU7B = crs_rec.dept, optional,
qualifier = "#XXXX,YYYY,ZZZZ,DDDD,EEEE";
LU7C = crs_rec.cat, optional,
qualifier = "field:PA6";
PA7: optional,
comments = "COMMENT_CRS_NO - COMMENT_BLANK_ALL"
default = "",
lookup LU7,LU7B,LU7C joining *crs_rec.crs_no,
upshift,
length = 10;
This would show only the courses in departments XXXX,YYYY,ZZZZ,DDDD, and EEEE in the catalog entered as param PA6.
(the catalog param is basically the only way of doing the "distinct" for the crs_no in the menuopt).
You cannot do the dept in div thing unless you make dept another parameter in which case you could limit the dept selection with a div qualifier and change the LU7B to reference field:xxxx (the param for the dept).

Resources