Contents
Guide to Making Software Changes
This document describes the core development guidelines for contributing to the xTuple development effort. It assumes very little about software development experience but is not a tutorial for software development, software development tools, or programming languages. Most of the content will be familiar to experienced software developers.
The current draft is aimed at employees of xTuple working internally. Future versions will address the processes for customer, reseller, and third-party contributions.
The reader should read and follow the steps outlined in DevelopmentEnvSetup before continuing with the steps below. The configuration document describes what tools you will need and how to obtain and install them.
Check with Trolltech to see if you need to get a commercial license for Qt.
Conventions:
.../name: The path to reach a certain file or directory. This may be a full- or relative-path. If the path starts with a slash (/) then you must specify the full path (this is rare).
prompt$ stuff: $ and anything before it is the prompt and stuff is what you type after it
Introductory Concepts
master copy of something vs. the copy that's actually used
the appropriate place(s) to make a change visible
what is part of the product and what is not
bug tracking
what are SVN and CVS?
SVN repository holds xtuple, xtupledocs, xtupleserver, updater, csvimport, openrpt on SourceForge
Read-access to the SourceForge repositories is available to everyone while write/commit access is restricted. If you want commit access, please contact xTuple.
There is a private repository for OpenMFG client and server files
how we use CVS and SVN: if you check in, everyone sees it when they update
naming conventions
backing out changes if you've really screwed up
if it's broke, fix it; if it ain't broke, don't break it
use the language to simplify
images in the application
Changes Independent of xTuple ERP
one-off changes vs. experimental work vs. not generally applicable
don't do it - maintenance - but if you must, create your own CVS or SVN repository for your own work and keep each feature or bug-fix isolated to individual checkins. There are strategies for updating your own repository from a master and keeping your changes.
Fixing Bugs
reproduce
confirm
assign
resolve - checkin as few times as possible (combine contents of multiple directories) and the comment should include "fixes bug #12345" or "fixes issue #12345" if it really fixes the problem, or leave off the word "fixes" if it's only part of the solution, such as an intermediate checkin. This wording automatically updates the Mantis issue, adding a note in all of these cases and actually marking the issue as resolved if the comment includes the word "fixes". Note that the # symbol is significant, as is the fact that there should be no space between the # and the issue number.
close
Adding Features
understand
add issue
spec
implement
resolve
accept
close
Some General Guidelines
If the code you're changing is broken (in some way other than what you're trying to change or fix), fix it anyway. There are only two exceptions:
- You know for a fact that someone else is working on fixing this problem.
- The product is approaching final release, as in you are making changes to a late beta release, a release candidate, or a final build.
If you are making additions to existing code, integrate your changes with the existing code. For example, if an existing stored procedure manipulates work orders with a status of Open and Exploded and you are trying to make it do the same thing with Imploded work orders, don't do this:
IF (_statusVar IN (O, E) THEN -- existing ... -- existing ELSEIF (_statusVar = I) THEN same ... -- duplicated code: Bad Programmer!
Do this instead:
IF (_statusVar IN (O, E, I) THEN ...
Changing Reports
Master copies of all reports live in the share/reports subdirectory of the xtuple repository.
- svn update your xtuple repository checkout
- Load reportname.xml into the database
- Make and test your changes
- Save your changes to the database as level 0 of the report
- Save your changes to
.../OpenMFG/ReportDefinitions/OpenMFG/reportname.xml
- If you had to use a level other than 0 for testing, remove the non-level 0 copy of the report from the database.
- svn diff reportname.xml and review the changes manually to make sure they look right
- svn commit reportname.xml
Put a short description of why you made this change in your checkin comment, including the Mantis issue number if there is one. The 'what' is clear from the differences between the previous version and what you checked in.
If this change is related to a Mantis issue, see the Fixing Bugs or Adding Features sections for further guidance.
Changing the GUI Client
One of the things we're trying to do to the existing code in OpenMFG is move the SQL out of the source code, particularly the more complex MetaSQL queries, and into a separate resource file which is imported into the database. This will eventually allow for patching some bugs without shipping whole binary packages, sharing queries between source files, and other neat things. To implement queries as resources:
- Change directory to the metasql directory (e.g. cd xtupleserver/dbscripts/metasql).
- Edit group-name.mql -- where group = the type of information (e.g. arHistory, inventoryHistory, salesOrderItems) and name = a qualifier for how the information might be used (e.g. detail, populate). Put the query, including MetaSQL tags if necessary, in this .mql file. The first three lines of the file must be comments that define the group, name, and notes associated with the .mql file. For example:
-- Group:arHistory -- Name:detail -- Notes:used by arWorkBench, dspAROpenItems
- Import the .mql file into the database using the openrpt/bin/importmqlgui utility.
- In the C++ source file that needs to call this query:
#include <metasql.h> #include "mqlutil.h" ... // in the method that calls the query ParameterList params; // if there are MetaSQL parameters to set then setParams(params); // either have a method that sets them or set them inline here MetaSQLQuery mql = mqlLoad("group", "name"); // group and name defined in the .mql file comments XSqlQuery myQuery = mql.toQuery(params); if (myQuery.first()) ... - Rebuild the application and test.
Adding Custom Widgets
Guidelines for developing widgets haven't yet been codified.
There are several steps required to implement a new widget for use in the application and make it visible in Qt Designer. Here they all are:
- Create the widget.cpp and widget.h file that implement your new widget in the widgets directory. The widget.h filename must be all lowercase regardless of the capitalization of widget.cpp or the class name.
- Create the widget's plug-in widgetplugin.h file in widgets/plugins. Copy and edit an existing plug-in header file to make sure you get all of the required information. If widget.cpp and widget.h implement more than one custom widget that you want visible in Qt Designer, create separate plug-in header files for each widget.
- Edit the widgets.pro file and add widgetplugin.h file(s) to the first HEADERS list, widget.cpp to the SOURCES list, and widget.h file to the second HEADERS list
- Edit OpenMFGWidgets.cpp and add an #include for widgetplugin.h and add an m_plugins.append() for the plug-in class.
- Rebuild the Makefiles in the widgets directory:
cd widgets rm Makefile* qmake
- Quit Qt Designer if you have it running.
- From the top source directory, not the widgets subdirectory, build the application:
cd .. make #or mingw32-make or ...
You may have to remove the old plug-in shared library manually for this to work. The plug-in shared library is named something like$QTDIR/plugins/designer/libxtuplewidgets.shared-library-suffix.
- Start Qt Designer.
Changing the Database Structure
The PostBooks and OpenMFG applications use very similar databases. The majority of tables, views, triggers, and stored procedures are shared. The xtupleserver SVN module holds scripts to create these shared views, triggers, and stored procedures. In addition, the scripts used to update individual aspects of the database structure from one release to the next, e.g. to add table columns or indexes, are also stored in the xtupleserver module. Any functionality or changes specific to OpenMFG should be checked in to the appropriate repository.
Here are the conventions for SQL scripts used to define or change aspects of the database structure:
- File names should end with the suffix .sql
- File names should consist entirely of lowercase letters except as noted below.
- Files which change the structure of existing tables should be named alterTablename.sql - note the uppercase letter at the beginning of the table name.
- Files which add tables, privileges, and indexes should be named createShortdescrip.sql - again note the one uppercase letter in the middle.
Create explicit transactions for alter and create scripts that have multiple lines in them. Use COMMIT to close these transactions, never the PostgreSQL extension END.
If you need to create a new database object then call the dropIfExists stored procedure before the CREATE line. This stored procedure knows how to delete tables, views, and triggers as of release 3.0, and constraints as of release 3.1. For example, if you are adding a new view for vendors to the api schema then start with the following:
BEGIN; SELECT dropIfExists('VIEW', 'vendor', 'api'); CREATE VIEW api.vendor ...- Disable triggers before running ALTER TABLE if possible. This will prevent problems where updates to tables cause triggers to execute and potentially fail because of alterations to one or more tables. This can be skipped if there is reason to do so but if you don't disable the triggers then document the required specific order of script execution.
ALTER TABLE table DISABLE TRIGGER ALL; -- make changes here ALTER TABLE table ENABLE TRIGGER ALL;
- Create a precheck.xml or add to an existing precheck.xml file a SELECT statement to search for any data that might cause a database upgrade to fail. This SELECT statement should return TRUE if the data can be successfully upgraded and FALSE if not. For example, if changing a column to a foreign key, the precheck statement should query that column and return TRUE if all values in the existing data meet the foreign key requirement and FALSE if some values do not refer to existing records. An example Precheck.template file is available in xtupleserver/updateScripts.
Changing Stored Procedures
Do not extract a stored procedure from a database to edit it; there are several reasons why this is a bad idea. Here is the correct process to follow:
- update your xtupleserver and OpenMFG-specific checkouts.
- change to the dbscripts/functions directory
- Find the file that contains the stored procedure(s) you need to change. Each file should be named after the stored procedure it contains.
- Make and test your changes to the stored procedure file. To test them, you will need to load your changes into the database. One way to do this is with the psql command line tool:
$ psql Password: database=# \i storedprocfilename
- svn diff storedprocfilename and review the changes manually to make sure they look right
- svn commit storedprocfilename
Put a short description of why you made this change in your checkin comment, including the Mantis issue number if there is one. The 'what' is clear from the differences between the previous version and what you checked in.
If this change is related to a Mantis issue, see the Fixing Bugs or Adding Features sections for further guidance.
Style:
Use IF ... ELSIF ... ENDIF; as much as possible. It's much easier to code correctly and maintain than IF ... ELSE IF ... ENDIF; ENDIF;
The preferred quoting method to wrap the body of a stored procedure is $$ quoting. Previously single-quoting alternatives were used to work with all of the versions of PostgreSQL that our customers use; however this is no longer a requirement and the $$ quoting is easier to read.
Changing Documentation
You may also want to edit the documentation, some of which is written in XML using DocBook for markup; some is written in xTupleWiki.
Adding Images to the application
First read Qt's documentation on the Resource Compiler (rcc). Here are the xTuple conventions:
- Try to use a PNG or XMP file for your image.
- Put the image file in the images subdirectory of the source code directory where the image is used by the application.
- If there isn't already a Qt Resource (.qrc) file in the source code directory or in the images subdirectory, create one and name it after the directory in which you put it (e.g. guiclient.qrc)
Make sure the resource path referred to by the source code matches the resource path in the .qrc file.
