Difference between revisions of "User:Jairah"

From ADempiere
Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.
(Window Converted Currency in SO/PO)
m (Creating user page for new user.)
 
(23 intermediate revisions by one other user not shown)
Line 1: Line 1:
[[Image:Jairah.jpg|left|thumbnail|Web Mistress of ADempiere.org]]
+
A citizen of Adempiere.
 
+
Started working and learning ADempiere 6 years ago, and helps create documentations by publishing information in the wiki page.
{{Userboxtop}}
+
I also have a startup for ADempiere consultancy in the Philippines: http://ajfl.tech
{{User real name|Jireh Arciaga}}
+
Now, I am working on understanding iDempiere and hopefully I and my team can contribute back to the community more than just documentation but also in testing and development.
{{User Philippines}}
+
{{User en}}
+
{{User Sourceforge|http://sourceforge.net/users/jairah}}
+
<!----{{User Facebook|http://www.facebook.com/people/Jairah-Jaijai/1031635194}}--->
+
<!----{{User Multiply|http://stately.multiply.com}}--->
+
{{User LCC|http://lcc.ph}}
+
{{User YEmail|jairah1225@yahoo.com}}
+
<!----{{User YMessenger|jaijai_1225@yahoo.com}}--->
+
{{Userboxbottom}}
+
 
+
*''So pay attention to how you listen. For to the one who has something, more will be given. However, from the one who doesn't have, even what he thinks he has will be taken away from him. '''(Luke 8:18)''''''
+
*''Whatever you do, work at it with all your heart, as working for the Lord, not for men, '''(Col 3:23)'''''
+
*''Do your own work well, and then you will have something to be proud of. But don't compare yourself with others. We each must carry our own load.'''(Galatians 6:4-5)'''''
+
*'''''Do not worry about anything, but pray and ask God for everything you need, always giving thanks. And God’s peace, which is so great we cannot understand it, will keep your hearts and minds in Christ Jesus.(Philippians 4:6-7 (NCV))'''''
+
 
+
 
+
===Want to know me better?===
+
 
+
----
+
 
+
First, as you can see, I'm a Christian, a God fearing person. My Lord and Savior is Jesus Christ the son of God. If you have something against Christians, please don't start asking any question/s that will lead to an argument or something like that, it's not healthy :). If you have questions about the website or anything that you think I can be of help, then I would gladly answer it ;D. You can easily approach me through yahoo email/messenger, as long as you introduce yourself :)
+
 
+
===Other things I do...===
+
 
+
----
+
 
+
*Programming
+
**PHP Language
+
**PHP Framework: Symfony
+
**Some basics of VB.Net
+
**Some basics of JAVA EE (servlets and jsp)
+
*Databases
+
**Once experimented on IBM DB2 (college days)
+
**MYSQL
+
**Studying more on Postgres Plus and Postgresql (currently)
+
*Drupal (currently CMS of Adempiere.org)
+
*I use Adobe Photoshop most of the time
+
*ERP Systems
+
**MFG/PRO (older version, mmm.. version of 8 years ago)
+
**Adempiere (planning on introducing to the higher management)
+
**Compiere
+
**OpenBravo (Did some minor Studies and Analysis)
+
**OpenTaps (Did some minor Studies and Analysis)
+
*Software Quality/Assurance
+
*Macromedia Flash Animation
+
 
+
===My Stress Relievers===
+
 
+
----
+
 
+
''(it might work on you too ;D)''
+
*I Listen to Music
+
**Pop / Slow Pop (most of the times)
+
**Alternative
+
**Punk / Rock (when I'm trying to forget something or trying not to think of something)
+
*Drawing Anime or anything I feel like drawing
+
*or I watch
+
**Anime / Japanese Drama
+
**House (latest season)
+
**Grey's Anatomy (latest season)
+
**CSI NY and Miami (when I have time)
+
**Ally McBeal (sometimes, when I feel like watching it)
+
**Gossip Girl (latest season)
+
**movies but I hate horror / suspense movies
+
*I go somewhere where I can spend some quite time alone :)
+
*Do anything I want (as long as I'm not doing my work)
+
*or I eat popcorns
+
*or I play
+
**(Desktop) Tower of Defense (Bloons or Kongregate)
+
**Facebook: Pet society (I like designing the house of my pet)
+
 
+
----
+
=Some of My Documentations=
+
''These are my own references based on some tutorials found also in this wiki. It's just that, for me, diagrams are much better than texts :D... If there are corrections, please contact me so I can change it immediately... :)''
+
 
+
===Adempiere 342s Production Flow===
+
[[Image:Production.jpeg]]
+
 
+
----
+
 
+
===Adempiere 342s Purchase Order (PO) Flow===
+
[[Image:Purchase_order.jpeg]]
+
 
+
----
+
 
+
===Adempiere Sales Order (SO) Map===
+
''Why sales order map? Well, when I was starting I'm having a hard remembering what sales order and how it produce it depending on its document type and other rules. I made this so I can quickly see what it generates and I don't like scanning articles just to search for one answer. Just sharing this for those who need it.. :)
+
 
+
GERMAN VERSION of Sales Order Map is available thanks to Thomas Kreser of Catura.de
+
 
+
Direct Image Link: http://www.adempiere.com/index.php/Image:Auftragsarten_in_ADempiere.png
+
 
+
Catura.de Blog: http://www.catura.de/blog/2010/04/20/adempiere-auftragsarten/?lang=en
+
 
+
[[Image:Sales_Order_MAP.png]]
+
 
+
===Inventory Management Flow===
+
Well, here it goes, a basic flowchart of inventory management using ADempiere's warehouse and Locators.
+
Based this from ADempiereReleaseManual.pdf[http://sourceforge.net/projects/adempiere/files/Documentation/All%20Documents/ADempiereReleaseManual.zip/download] by Red1. (NOTE: Basic flow only)
+
[[Image:Inventory_Management.png]]
+
----
+
 
+
===Adempiere Libero: BOM===
+
''Setting up BOM''
+
 
+
'''*First, create all the product you'll be using for BOM. '''
+
 
+
Example: Orange Juice
+
 
+
You have to have the following products: Orange Juice, Orange, Water, and Packaging
+
 
+
You've noticed that the BOM checkbox in ADempiere Libero is disabled, while in Standard ADempeire, it's not, right?
+
It was disabled because the system will be checking it for your after you setup your BOM under Bill of Materials and Formula.
+
''(Manufacturing Management->Engineering Management->Bill of Materials & Formulas->Bill of Materials & Formula)''
+
 
+
Put inventory in your product. You can put inventory by Purchasing, by MO (but you have to have BOM for MO, so let's skip that)
+
or by setting your product type to resource or service. Example: Water as resource :)
+
 
+
'''*Next, create your BOM in Bill of Materials & Formula window.'''
+
#Choose the product your going to produce ''(Example: Orange Juice)''
+
#Fill out the other needed fields and Click Save
+
#Click New under Components of the BOM & Formula
+
#Put all the products you need in creating your product mentioned above ''(Example: Orange, Water, and Packaging)''
+
#Click Save
+
 
+
Now, go back to the product window and look at the product Orange Juice.
+
You will notice that checkbox BOM is now checked and it has now a verify button under it.
+
Basically, that's how you create BOM for Adempiere Libero. :)
+
 
+
----
+
===Understanding Libero===
+
''These are the documents that I've used that helped me understand Libero Manufacturing. Thanks to Victor,Bcahya,Red1, and other people in the community for being patient with me. Thanks also to these documents... :)
+
 
+
====ADempiere Libero: Manufacturing====
+
I was able to understand some of Libero's function, because of this tutorial [http://www.adempiere.com/images/b/b4/UserManualPartC-en.pdf] by [[User:Vpj-cd]].
+
This might not be the latest but it explains the basic quite well, and if you'll think more you'll notice that the difference wasn't that big. Thanks to Victor for providing this.
+
 
+
====ADempiere Libero: Manufacturing Sample Data====
+
If you are not sure whether you're using the right data for the function you're testing, here's a pdf that will help you understand more of what and where you should put the data that you're processing. Here's the link [http://www.adempiere.com/images/3/37/ManufacturingWorkshop_CORREGIDO.pdf] thanks again to [[User:Vpj-cd]] for sharing this really helpful documentation. It sure helped me a lot! :)
+
 
+
===Notes===
+
These are my notes... meaning, these are the things I wanted to take not since I haven't read this in any documentation... :)
+
===='''In setting up a new client in Adempiere:'''====
+
When I used the name TestClient I couldn't add a Model Class Validator in Client's window, but if I'm going to use a different name like MyCompany (as long as it doesn't start with test), then I could put a class validator. :D
+
===='''Using Physical Inventory:'''====
+
You use physical inventory if there's a discrepancy between system's inventory and warehouse inventory. Usually, if you check your warehouse (some monthly and some yearly, it depends on the company) and found out that some stuff were stolen/not good anymore, you'll use '''Physical Inventory''' to change the number of inventory in the system...but, you have to setup product cost first...
+
# go to Product Cost
+
# enter name of the product.. 
+
# go to product cost tab
+
# add a product cost like standard costing (sometimes it already has so you don't have to make one, just change the value if it's 0 to 1 or the cost of your product :) )...
+
# fill the current cost price
+
# then try again the to complete the Physical inventory where the product you named is exist.
+
I got this from this forum: https://sourceforge.net/forum/forum.php?thread_id=3332125&forum_id=610548
+
The reason why you have to add cost when changing Physical Inventory is for accounting purposes. They have to have record of those stolen or whatever-happened-to-that product in their record.
+
===='''Getting the Current Log in User:'''====
+
Go to the column in Table&Column window; make sure you choose the right table and column.
+
Example, in SalesRep_ID @ Purchase Order window
+
# Log in as System Admin
+
# Go to Table and Column
+
# Look for C_Order table
+
# Go to Column tab and look for SalesRep_ID
+
# Set Reference to Table Direct
+
# Set Dynamic Validation to AD_User - Internal
+
# Go to Default Logic field
+
# Add @#AD_User_ID@
+
# Log out then log in again as the user (not SuperUser)
+
''If it did not work, check if the user you used is a sales representative. That is why it will not work if you are going to use SuperUser as your log in user.''
+
===='''Setting up Purchase Product properly'''====
+
# Go to Product window
+
# Fill up the Product Tab
+
# Fill the Purchase Tab (or else you won't be able to convert Requisitions to PO)
+
# Fill up the Price Tab (this is always needed unless your product is Resource)
+
Got this from this forum: [https://sourceforge.net/projects/adempiere/forums/forum/610547/topic/3410599]
+
===='''Could not save changes - data was changed after query...'''====
+
I encountered this problem when I added an additional checkbox, so if you added one and has been encountering this error, here's what you're missing...
+
'''Just make sure you put a default value Y/N, depending on your need.'''
+
 
+
Got it from this forum: https://sourceforge.net/projects/adempiere/forums/forum/610547/topic/3245278
+
 
+
===='''Linking Tabs'''====
+
I'll assume that you have 2 working tabs for this one and you wanted to link the 1st tab to the second tab. Just fill up the '''Tab Level''' under Window, Tab and Field->Tab you can see that it's one of the field there. In Sales Order the Order tab is Tab Level 1 and for its Order Line it's Tab Level 2.
+
Hope this helps! :D
+
 
+
Got this from this topic: https://sourceforge.net/projects/adempiere/forums/forum/610547/topic/2099308
+
 
+
===='''Sales Order & Purchase Order in one Table'''====
+
As you know, they both shares one table: '''C_Order'''
+
How did they separate Sales Order data to Purchase Order data?
+
It's simple, just go to Windows, Tab and Fields -> Tab
+
Then you'll see the '''SQL Where''' field (in SO/PO it's IsSOTrx='Y' or IsSOTrx='N')
+
IsSOTrx = Is Sales Order Transaction
+
 
+
Hope this helps... :)
+
Reference: https://sourceforge.net/projects/adempiere/forums/forum/610548/topic/3457710
+
 
+
===='''New Attribute Set Instance (ASI)'''====
+
New ASI was being created during:
+
- Purchase: Material Receipt
+
- Production: Order Receipt & Issue
+
 
+
===='''Tracing the newly created ASI in production'''====
+
After searching and looking for tables where newly created ASI was being stored after Order Recipt and Issue, we've come up with an sql, hope this helps. (Pls msg me if you think there's a better way ^_^)
+
 
+
SELECT pcc.M_AttributeSetInstance_ID, pcc.M_Locator_ID
+
FROM PP_Cost_Collector pcc
+
LEFT JOIN PP_Order ppo ON (pcc.PP_Order_ID=ppo.PP_Order_ID)
+
WHERE ppo.PP_Order_ID=<PP_Order_ID - just find your way how to get it>
+
AND pcc.M_Product_ID=ppo.M_Product_ID
+
AND ppo.M_Product_ID=<M_Product_ID - get the product stated in PP_Order table>
+
AND pcc.M_AttributeSetInstance_ID <> 0
+
 
+
===='''No Info Column Error'''====
+
I often get this error because I often miss two important configuration.
+
First, the Window field in Table&Column. Meaning what window is this table being used. And secondly, the Identifier of column in Table&Column. So if you get this error, make sure you check both details. :)
+
 
+
===='''Restrict/Filter List Validation'''====
+
You can filter/restrict some parts using dynamic validation.
+
(('@field1@'='item1' AND AD_Ref_List.Value IN ('item3', 'item4)) OR ('@field1@'='item2' AND AD_Ref_List.Value IN ('item5', 'item6))
+
This code was mentioned by Carlos Ruiz in this forum: http://sourceforge.net/projects/adempiere/forums/forum/610548/topic/3143345
+
 
+
===='''Libero Costing Method'''====
+
Support standard costing for now.
+
Reference: http://sourceforge.net/projects/adempiere/forums/forum/639404/topic/3663017
+
 
+
===='''Order Policy'''====
+
Reference: http://www.adempiere.com/index.php/Adempiere_Business_Solution_UAL
+
# Fix Order Quantity: Establish fix quantity for every order created
+
# Lot for Lot: If you have 5 in demand order, each demand is equivalent to one order
+
# Period Order Quantity: If you have 5 Order Period then it sum all the requirements you need for 5 days. If you need 4 product to be produced each day, you'll be having an order with 20 products to be produced.
+
Ex: 5days * 4product/day = one planned order
+
 
+
===='''Getting Environmental Variables'''====
+
All values that you can see under Tools > Preferences > Context like AD_Org_Name can be called through this line:
+
String OrgName = Env.getContext(getCtx(), "#AD_Org_Name");
+
 
+
===='''Duplicate Key: Used 3rd Party Software to Import Data'''====
+
Always run the Sequence Check whenever you use a third party software that will populate your table or database. If you don't do this you'll receive a duplicate key error. :)
+
Reference: https://sourceforge.net/projects/adempiere/forums/forum/610548/topic/3378014
+
 
+
===='''NoPlantForWarehouseException'''====
+
It's because your BOM Type is Make-To-Order.
+
Meaning, upon ordering, ADempiere will produce, but how can it properly produce if you don't have Product Plan? :)
+
 
+
===='''UOM, UOM, UOM!!!'''====
+
And I have to learn this in our production test. I'm glad it's still a test (in production environment)
+
# PRODUCT window - UOM : your product's uom. Ex: Orange Juice 250mL
+
# BOM window - UOM: your production's uom. You have to change this if you'll be producing, example, a CARTON of Orange Juice.
+
# UOM Conversion tab - here you'll have to put how your product is converted; Under mL UOM create a conversion to POUND, Let's say 1CTN = 2500mL
+
# SALES ORDER Line tab - UOM of the order. Ex: A customer ordered 50 CTN of Orange Juice, you have to choose CARTON instead of mL. You'll see in Ordered Quantity field the converted 50 CTNs in mL.So you should have 125,000mL (50 * 2500) in PO Quantity of Manufacturing Order window :)
+
 
+
===='''Price and UOM Standard Precision'''====
+
If you want to change the decimal places in your PO Line or SO Line Unit Price, then the best way is to change UOM Standard Precision. If your UOM is KG then change KG's standard precision. :)
+
 
+
===='''Sales Order Converted Currency Line'''====
+
Located in org.compiere.model.GridTab
+
 
+
Check getTrxInfo()
+
 
+
From: [https://sourceforge.net/projects/adempiere/forums/forum/611163/topic/3678714]
+
 
+
===='''Callout: Check Cursor in Field'''====
+
You can do this if you want to execute a certain code if the cursor is in the specified field.
+
 
+
mField.getColumnName().equals("<column_name>") // replace <column _name> to actual column name
+
 
+
More example? Look into CalloutOrder class in '''amt''' method. :)
+
 
+
===='''Manufacturing: Component Check'''====
+
I found a very interesting conversation about Component Check :)
+
About No Component Check result...
+
Check it out here: [https://sourceforge.net/projects/adempiere/forums/forum/610548/topic/3928793/index/page/1]
+
 
+
===='''Non-terminating decimal expansion'''====
+
When you divide don't forget to round, just in case it will return an infinite result...
+
  var1.divide(var2, 2, RoundingMode.HALF_UP)
+
source website: [http://jaydeepm.wordpress.com/2009/06/04/bigdecimal-and-non-terminating-decimal-expansion-error/]
+
 
+
===='''Window Converted Currency in SO/PO'''====
+
If you wan't to change the way it's being computed, you can find the code under
+
 
+
org.compiere.model.GridTab
+
under getTrxInfo() method.
+
 
+
Thanks to Carlos for this information.
+
forum: [http://sourceforge.net/projects/adempiere/forums/forum/611163/topic/3678714]
+
 
+
----
+
 
+
===Can not select multiple records in a table? Here is a way...===
+
You have to create an array list of objects of that certain class.
+
 
+
Example: I want to select all the Movement Lines and I don't want to use try and catch just to be able to SELECT it.
+
SQL: SELECT * FROM M_MovementLine (you can add WHERE Clause if you want, just like any normal SQL)
+
 
+
  public static MMovementLine[] getLines (Properties ctx, Integer M_Movement_ID, Integer M_Product_ID, String trxName)
+
  {
+
  String sql = "";
+
 
+
  ArrayList<MMovementLine> list = new ArrayList<MMovementLine>();
+
 
+
  sql="SELECT *" +
+
  " FROM M_MovementLine" +
+
  " WHERE M_Movement_ID=?";
+
 
+
  if(M_Product_ID!=0)
+
  sql+=" AND M_Product_ID=?";
+
 
+
  PreparedStatement pstmt = null;
+
  ResultSet rs = null;
+
  try
+
  {
+
  pstmt = DB.prepareStatement (sql, trxName);
+
  pstmt.setInt(1, M_Movement_ID);
+
  if(M_Product_ID!=0)
+
      pstmt.setInt(2, M_Product_ID);
+
  rs = pstmt.executeQuery ();
+
  while (rs.next ())
+
  list.add(new MMovementLine (ctx, rs, trxName)); //this is the code that adds to arraylist
+
  }
+
  catch (SQLException ex)
+
  {
+
  s_log.log(Level.SEVERE, sql, ex);
+
  }
+
  finally
+
  {
+
  DB.close(rs, pstmt);
+
  rs = null; pstmt = null;
+
  }
+
  MMovementLine[] retValue = new MMovementLine[list.size()];
+
  list.toArray(retValue);
+
  return retValue;
+
}
+
+
I've placed this code under MMovementLine class.
+
Now, calling this ArrayList, I have to use for each loop.
+
 
+
  MMovementLine[] lines = MMovementLine.getLines(getCtx(), MovementID, 0, get_TrxName());
+
  for(MMovementLine line:lines){
+
          int x = line.getLine();
+
          int ID = line.getM_Movement_ID();
+
          //other codes
+
  }
+
 
+
TrxName is important so that there will be no changes executed until the whole process is done.
+
 
+
Hope this helps. :)
+
 
+
----
+
 
+
===Creating a Button with Process (Report&Process)===
+
For some reason in Inventory Move window, the button Create Lines (from certain table) isn't working...
+
I posted a question in the forum but I didn't get any answer. I thought, maybe there really is no process in this button and maybe the people who read my question knew that there really is no process for that, and it's not a bug, since I asked if it's a bug or not.
+
 
+
Anyway, I have to find a way to create a button with process in it. A process that will copy all the details from a specific table and post in Move Line tab.
+
 
+
Btw, if you really want to try this out, you should have a Development Environment, http://www.adempiere.com/index.php/Create_your_ADempiere_development_environment
+
 
+
Scenario: I have to copy the lines from Material Receipt window or M_InOutLine table and insert it too in M_MovementLine.
+
 
+
'''Table and Column:'''
+
# DB Column Name: GenerateList
+
# System Element: GenerateList
+
# Name: Generate List
+
# Length: 1
+
# Reference: Button
+
# Process: Create Movement Line List (you can only put process here if you have made the process; for this case, since you haven't made one just leave it blank)
+
 
+
'''Widow, Tab and Field'''
+
# Name: Copy MR Lines (since I'll copy the Material Receipt lines)
+
# Description: Generate List
+
# GenerateList_Generate List
+
Display Length: 22
+
 
+
'''Report and Process'''
+
 
+
For those who are curious how I did this, I used InventoryCountCreate class as my basis. :P
+
Disclaimer: This is my first time creating a java process, so if there are some corrections or best coding style that you can recommend to me so I can update this, please don't hesitate, I would love to hear your opinion. :)
+
 
+
Here comes the climax of this note! :D
+
 
+
# Search Key: M_Movement Create
+
# Name: Create Movement Line List
+
# Description: Create Movement Line List
+
# Comment/Help: This will create the movement line based on Material receipt selected
+
# Data Access Level: Client+Organization
+
# Classname: org.compiere.process.CopyMRLine (put the location with class name here)
+
 
+
Parameters for this process are:
+
# Material Receipt (M_InOut_ID)
+
# Source Warehouse (M_Locator_ID)
+
# Target Warehouse (M_LocatorTo_ID)
+
 
+
Note: In my material receipt ID, I want it to be read only and has default value, so under Default Logic, I placed this code @M_InOut_ID@ (this will automatically put value in my Material Receipt field.
+
 
+
You need to fill the mandatory fields in Movement line to be able to successfully create the lines and save it. For this, we have to make sure Locator from and to is not null.
+
 
+
Here's the code... Place it under org.compiere.process
+
 
+
package org.compiere.process;
+
+
import java.math.BigDecimal;
+
import java.sql.PreparedStatement;
+
import java.sql.ResultSet;
+
import java.util.logging.Level;
+
import org.compiere.model.MMovement;
+
import org.compiere.model.MMovementLine;
+
import org.compiere.util.AdempiereSystemError;
+
import org.compiere.util.DB;
+
import org.compiere.util.Env;
+
+
public class CopyMRLine extends SvrProcess{
+
+
/** Inventory Movement Parameter */
+
private int p_M_Movement_ID = 0;
+
/** Material Receipt Parameter */
+
private int p_M_InOut_ID = 0;
+
+
/** Inventory Movement */
+
private MMovement m_movement = null;
+
/** Locator Parameter */
+
private int p_M_Locator_ID = 0;
+
/** Locator To Parameter */
+
private int p_M_LocatorTo_ID = 0;
+
+
/** Inventory Movement Line */
+
private MMovementLine m_mline = null;
+
+
+
/**
+
*  Prepare - e.g., get Parameters.
+
*/
+
// This is how you get your parameter that you'll be passing from Report&Process Parameter
+
protected void prepare()
+
{
+
ProcessInfoParameter[] para = getParameter();
+
for (int i = 0; i < para.length; i++)
+
{
+
String name = para[i].getParameterName();
+
if (para[i].getParameter() == null)
+
;
+
else if (name.equals("M_InOut_ID"))
+
p_M_InOut_ID = para[i].getParameterAsInt();
+
else if (name.equals("M_Locator_ID"))
+
p_M_Locator_ID = para[i].getParameterAsInt();
+
else if (name.equals("M_LocatorTo_ID"))
+
p_M_LocatorTo_ID = para[i].getParameterAsInt();
+
else
+
log.log(Level.SEVERE, "Unknown Parameter: " + name);
+
}
+
p_M_Movement_ID = getRecord_ID();
+
} //prepare
+
+
/**
+
* Process
+
* @return message
+
* @throws Exception
+
*/
+
protected String doIt () throws Exception
+
{
+
log.info("M_Movement_ID=" + p_M_Movement_ID
+
+ ", M_Locator_ID=" + p_M_Locator_ID + ", M_LocatorTo_ID=" + p_M_LocatorTo_ID);
+
m_movement = new MMovement (getCtx(), p_M_Movement_ID, get_TrxName());
+
if (m_movement.get_ID() == 0)
+
throw new AdempiereSystemError ("Not found: M_Movement_ID=" + p_M_Movement_ID);
+
if (m_movement.isProcessed())
+
throw new AdempiereSystemError ("@M_Movement_ID@ @Processed@");
+
//
+
+
StringBuffer sql = new StringBuffer(
+
"SELECT iol.M_Product_ID, iol.M_Locator_ID, iol.M_AttributeSetInstance_ID, s.QtyOnHand" +
+
" FROM M_InOutLine iol" +
+
" INNER JOIN M_Storage s ON (s.M_Product_ID=iol.M_Product_ID)" +
+
" WHERE iol.AD_Client_ID=?" +
+
" AND s.M_Locator_ID = iol.M_Locator_ID" +
+
" AND s.M_AttributeSetInstance_ID=iol.M_AttributeSetInstance_ID" +
+
" AND iol.IsActive='Y'");
+
//
+
if (p_M_Locator_ID != 0)
+
sql.append(" AND s.M_Locator_ID=?");
+
//
+
if (p_M_InOut_ID != 0)
+
sql.append(" AND iol.M_InOut_ID=?");
+
+
int count = 0;
+
PreparedStatement pstmt = null;
+
try
+
{
+
pstmt = DB.prepareStatement (sql.toString(), get_TrxName());
+
int index = 1;
+
pstmt.setInt (index++, m_movement.getAD_Client_ID());
+
+
if (p_M_Locator_ID != 0)
+
pstmt.setInt(index++, p_M_Locator_ID);
+
if (p_M_InOut_ID != 0)
+
pstmt.setInt(index++, p_M_InOut_ID);
+
+
ResultSet rs = pstmt.executeQuery ();
+
while (rs.next ())
+
{
+
int M_Product_ID = rs.getInt(1);
+
int M_Locator_ID = rs.getInt(2);
+
int M_AttributeSetInstance_ID = rs.getInt(3);
+
BigDecimal MovementQty = rs.getBigDecimal(4);
+
if (MovementQty == null)
+
MovementQty = Env.ZERO;
+
//
+
+
count += createMovementLine (M_Locator_ID, p_M_LocatorTo_ID, M_Product_ID,
+
M_AttributeSetInstance_ID, MovementQty);
+
}
+
rs.close ();
+
pstmt.close ();
+
pstmt = null;
+
}
+
catch (Exception e)
+
{
+
log.log(Level.SEVERE, sql.toString(), e);
+
}
+
try
+
{
+
if (pstmt != null)
+
pstmt.close ();
+
pstmt = null;
+
}
+
catch (Exception e)
+
{
+
pstmt = null;
+
}
+
+
+
//
+
return "@M_MovementLine_ID@ - #" + count;
+
} //doIt
+
 
+
The code below will be creating a new line in Inventory Move line. What it does is it copies the line in MR Line and put it in Move Line. Just add this under the code from above (but still inside the class).
+
+
/**
+
* Create/Add to Inventory Move Line
+
* @param M_Product_ID product
+
* @param M_Locator_ID locator
+
* param M_LocatorTo_ID locatorto
+
* @param M_AttributeSetInstance_ID asi
+
* @param QtyOnHand qty
+
* @param M_AttributeSet_ID as
+
* @return lines added
+
*/
+
private int createMovementLine (int M_Locator_ID, int M_LocatorTo_ID, int M_Product_ID,
+
int M_AttributeSetInstance_ID, BigDecimal MovementQty)
+
{
+
+
// new line
+
m_mline = new MMovementLine (m_movement, M_Locator_ID, p_M_LocatorTo_ID,
+
M_Product_ID, M_AttributeSetInstance_ID, MovementQty);
+
if (m_mline.save())
+
return 1;
+
return 0;
+
} // createMovementLine
+
+
}
+
 
+
Also, you have to have this code added to MMovementLine (org.compiere.model). This is the one who'll be setting the values to Movement Line. (please don't forget to put comments/mark in your added line so it won't get mixed up the the default codes)
+
 
+
public MMovementLine (MMovement movement,
+
int M_Locator_ID, int M_LocatorTo_ID, int M_Product_ID,
+
int M_AttributeSetInstance_ID, BigDecimal MovementQty)
+
{
+
this (movement.getCtx(), 0, movement.get_TrxName());
+
if (movement.get_ID() == 0)
+
throw new IllegalArgumentException("Header not saved");
+
m_parent = movement;
+
setM_Movement_ID (movement.getM_Movement_ID()); // Parent
+
setClientOrg (movement.getAD_Client_ID(), movement.getAD_Org_ID());
+
setM_Locator_ID (M_Locator_ID); // FK
+
setM_LocatorTo_ID (M_LocatorTo_ID); // -added by jai
+
setM_Product_ID (M_Product_ID); // FK
+
setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
+
setMovementQty (MovementQty);
+
//
+
+
} // MMovementLine
+
 
+
 
+
There you go! :) A button with process that copies lines from MR to Inventory Move Line.
+
 
+
 
+
----
+
 
+
 
+
==='''Creating COMPLETE button'''===
+
First, you have to make sure you have a process for your Complete button.
+
You could try imitating some of the complete button process like M_Movement_Process.
+
Go to DocAction column of M_Movement table, there you can see the process and how it is built.
+
Just go and zoom and you know what to do ;)
+
 
+
Here's the real deal...
+
You must complete all the needed methods for your M classes. (EX: MMovement)
+
Then implement DocAction (public class MMovement extends X_M_Movement implements DocAction)
+
 
+
The following columns are needed for parent table:
+
# DocStatus
+
# DocAction
+
# DocType (but I you can not put it if you don't need it, just replace the value you have to return for its method)
+
# Description
+
# IsApproved
+
# DocumentNo
+
# Reversal_ID
+
# Processed
+
# Processing
+
*At least, these are the fields/columns that I needed to create a simple Complete button with close and complete choices.
+
 
+
The following columns are needed for the child table:
+
# Description
+
# Line
+
# Processed
+
# ReversalLine_ID
+
# Posted
+
 
+
Then, these are the methods you have to have in you M class.
+
(At least, these are the methods I needed to complete the button.)
+
Btw, you can add any code you like, I'm just giving the overview... :)
+
 
+
This is the default flag that was being used, that's why I used this too.
+
 
+
/** Just Prepared Flag */
+
private boolean m_justPrepared = false;
+
/** Process Message */
+
private String m_processMsg = null;
+
 
+
 
+
public MCUSTableA (Properties ctx, int CUS_TableA_ID, String trxName)
+
{
+
super (ctx, CUS_TableA_ID, trxName);
+
if (CUS_TableA_ID == 0)
+
{
+
// setC_DocType_ID (0);
+
setDocAction (DOCACTION_Complete); // CO
+
setDocStatus (DOCSTATUS_Drafted); // DR
+
}
+
} // CUS_WorkOrder
+
 
+
 
+
public MCUSPallet[] getLines (boolean requery)
+
{
+
//...your codes...
+
}
+
 
+
 
+
This process (processIt) is important because it processes DocAction; it is called every time you process a document whether Complete/Prepare/Void/etc... (c/o: Mark Libunao)
+
 
+
public boolean processIt (String processAction)
+
{
+
m_processMsg = null;
+
DocumentEngine engine = new DocumentEngine ((DocAction)this, getDocStatus());
+
return engine.processIt (processAction, getDocAction());
+
} // processIt
+
 
+
 
+
public String prepareIt()
+
{
+
log.info(toString());
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE);
+
if (m_processMsg != null)
+
return DocAction.STATUS_Invalid;
+
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
+
if (m_processMsg != null)
+
return DocAction.STATUS_Invalid;
+
+
m_justPrepared = true;
+
if (!DOCACTION_Complete.equals(getDocAction()))
+
setDocAction(DOCACTION_Complete);
+
return DocAction.STATUS_InProgress;
+
} // prepareIt
+
 
+
 
+
public String completeIt()
+
{
+
// Re-Check
+
    if (!m_justPrepared) {
+
        String status = prepareIt();
+
        if (!DocAction.STATUS_InProgress.equals(status))
+
            return status;
+
    }
+
+
    m_processMsg = ModelValidationEngine.get().fireDocValidate(this,
+
            ModelValidator.TIMING_BEFORE_COMPLETE);
+
    if (m_processMsg != null)
+
        return DocAction.STATUS_Invalid;
+
+
    // simple - we don't check anything here
+
+
    // User Validation
+
    String valid = ModelValidationEngine.get().fireDocValidate(this,
+
            ModelValidator.TIMING_AFTER_COMPLETE);
+
    if (valid != null) {
+
        m_processMsg = valid;
+
        return DocAction.STATUS_Invalid;
+
    }
+
 
+
 
+
public String getSummary()
+
{
+
StringBuffer sb = new StringBuffer();
+
sb.append(getDocumentNo());
+
// : Total Lines = 123.00 (#1)
+
sb.append(": ")
+
.append(Msg.translate(getCtx(),"ApprovalAmt")).append("=").append(getApprovalAmt())
+
.append(" (#").append(getLines(false).length).append(")");
+
// - Description
+
if (getDescription() != null && getDescription().length() > 0)
+
sb.append(" - ").append(getDescription());
+
return sb.toString();
+
} // getSummary
+
 
+
+
/**
+
* Reject Approval
+
* @return true if success
+
*/
+
public boolean rejectIt()
+
{
+
log.info(toString());
+
setIsApproved(false);
+
return true;
+
} // rejectIt
+
 
+
 
+
/**
+
  * Reverse Accrual - none
+
  * @return false
+
  */
+
public boolean reverseAccrualIt()
+
{
+
log.info(toString());
+
// Before reverseAccrual
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSEACCRUAL);
+
if (m_processMsg != null)
+
return false;
+
+
// After reverseAccrual
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSEACCRUAL);
+
if (m_processMsg != null)
+
return false;
+
+
return false;
+
} // reverseAccrualIt
+
 
+
+
/**
+
  * Close Document.
+
  * @return true if success
+
  */
+
public boolean closeIt()
+
{
+
log.info(toString());
+
// Before Close
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE);
+
if (m_processMsg != null)
+
return false;
+
+
// After Close
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE);
+
if (m_processMsg != null)
+
return false;
+
+
// Close Not delivered Qty
+
setDocAction(DOCACTION_None);
+
return true;
+
} // closeIt
+
 
+
 
+
/**
+
  * Reverse Correction
+
  * @return false
+
  */
+
public boolean reverseCorrectIt()
+
{
+
log.info(toString());
+
// Before reverseCorrect
+
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT);
+
if (m_processMsg != null)
+
return false;
+
}
+
 
+
Ok, it seems like a lot so it's better if you just visit the following function I'll be putting in MMovement class (I used it as my basis).
+
*public void addDescription (String description)
+
*public void setProcessed (boolean processed)
+
*private boolean m_reversal = false; // this is a variable; reversal flag
+
*private void setReversal(boolean reversal)
+
*private boolean isReversal()
+
*public boolean unlockIt()
+
*public boolean invalidateIt()
+
*public String getDocumentInfo()
+
*public int getDoc_User_ID()
+
*public boolean  approveIt()
+
*public int getC_Currency_ID()
+
*public boolean reActivateIt()
+
*public String getProcessMsg()
+
*public boolean voidIt()
+
*public File createPDF ()
+
*public File createPDF (File file)
+
 
+
After creating all those methods, just do some minor tweaks here and there just to make it work and put all the codes like updates that you want under completeIt() (if there's something you want to be updated after completion), and you're done. :)
+
 
+
Here's the link to the forum where I asked for some help about this button: https://sourceforge.net/projects/adempiere/forums/forum/610548/topic/3468001/index/page/1
+
 
+
[[Category:Developer documentation]]
+

Latest revision as of 06:58, 5 May 2016

A citizen of Adempiere. Started working and learning ADempiere 6 years ago, and helps create documentations by publishing information in the wiki page. I also have a startup for ADempiere consultancy in the Philippines: http://ajfl.tech Now, I am working on understanding iDempiere and hopefully I and my team can contribute back to the community more than just documentation but also in testing and development.