Open Sage

Discussion Topics => Open Source => Topic started by: John Spikowski on September 24, 2021, 11:49:09 pm

Title: Project Announcement
Post by: John Spikowski on September 24, 2021, 11:49:09 pm
I would like to propose to the Sage 100 customer base an alternative to signing up for the subscription plan after you already bought the software. I personally think it's wrong to cripple and penalize customers that wish to hold Sage to the original contract when they purchased the software. I'm an open source advocate and maintain an open source scripting language. (ScriptBasic) I host a number of BASIC related forums as well.

I'm not a fan of Node.js, Java or Python. I do like PHP for web applications. Most blogs, forums and CMS packages are written in PHP using MySQL as the DB. I have been toying with the idea of using Front Accounting as a migration path for Sage 100 customers that want off or not get on the subscription bus.

I'm in the process of creating a data migration utility for FA from Sage 100. If you would like to participate with this effort than please join the forum which will give you access to a section of the forum reserved for this project. I like the framework FA developed and the active community involvement with the project. I would like to fork FA and enhance it to meet the functional standards 100 established.

Sales And Accounts Receivables
Purchases and Accounts Payable
Inventory and Stocks
Manufacturing
Fixed Assets
Dimensions
Cash and Bank
General Ledger
Reports
Access Levels and Adaptations
Advanced Features
Language Support
Other Details

I have installed Front Accounting (2.4.10) on the OpenSage.org site for this project. It runs really well. Members of the forum will have access to this development fork to work with. I'm also going to create a repository for the project in the https://basic-sandbox.us Gitlab-ce I host for code contributions.

Front Accounting Home Page (https://frontaccounting.com/)

(https://frontaccounting.com/wbt/media/fa_dash.jpg)

I have attached a few screen shots from the installed copy here on the Open Sage site.

There is a DEMO install on the Front Accounting site you can evaluate the software to see if it would fit your needs.   
Title: Re: Project Announcement
Post by: John Spikowski on September 28, 2021, 12:31:46 am
I have created a repository for the Open Sage ERP project. Those who join the forum and wish to participate in this project will be giving the ability to submit enhancements. Hosting and taking on a project manager role is my initial contribution to the project. I hope others will join in and contribute their talents to the project.

OS-ERP - Open Sage ERP Repository (https://gitlab.com/open-sage/os-erp)
Title: Re: Project Announcement
Post by: John Spikowski on September 29, 2021, 09:52:20 pm
Here is my list of advantages using OS ERP.

My favorite open source post of the day.

Quote
I think the developers are looking at experienced programmers like you to suggest a solution, This is what open source is all about. A community collaboration. So if you think you have a solution then suggest it. If they see it feasible they will include it.
Title: Re: Project Announcement
Post by: John Spikowski on September 30, 2021, 12:07:08 am
I was happy to discover that a Payroll / HR extension is available for FA.
Title: Re: Project Announcement
Post by: John Spikowski on October 01, 2021, 10:40:43 pm
I view this project as an insurance policy if Sage continues in their free fall. I have offered to facilitate and act as a project manager as my initial contribution to the project. I'm not doing this alone. If this is going to be successful then Sage 100 customers, partners and developers need to participate and make this a community effort. As of this point no one has registered on the forum and shown interest in the project. I hope that changes soon.

I feel the first task on the list is a Sage 100 migration utility. This will allow users to quickly evaluate the package without much effort using their own data.

If you need help setting up Open Sage ERP (Front Accounting) on a web hosting site let me know. My suggestion is to get a copy running and see if it will fill your needs as is. I would like to hear what you like or dislike about the package and what you feel may be missing.

Thanks in advance for your participation.

Title: Re: Project Announcement
Post by: John Spikowski on October 03, 2021, 12:52:32 pm
I have updated the OS-ERP repository with the updates and bug fixes since the 2.4.10 release. If you are going to install Open Sage ERP (Front Accounting) you should download the code from the repository rather than the Front Accounting site.

https://gitlab.com/open-sage/os-erp

The project needs help in the following areas.
 


Title: Re: Project Announcement
Post by: John Spikowski on October 04, 2021, 11:02:41 pm
I was able to install OS-ERP (Front Accounting) local on one of my Windows 10 Pro laptops. The first step is to install XAMPP 64 bit which installs Apache, MySQL and phpMyAdmin for database maintenance. I than download the OS-ERP repository into my C:\xampp\htdocs\fademo directory. I created a database with phpmyadmin prior to running the OS-ERP install by pointing your browser to localhost/fademo URL.

Hint:  The default user for MySQL is root with no password.
Title: Re: Project Announcement
Post by: John Spikowski on October 09, 2021, 03:44:22 pm
I downloaded the MySQL sample database which I plan to use to build the OS-ERP demo database. It provides the core tables to get something going.

This is the classicmodels DB in SQL format I found on Github if you want to get an idea what the data looks like.

https://github.com/hhorak/mysql-sample-db/blob/master/mysqlsampledatabase.sql

REST API

I noticed an extension module for FA that provides a REST API. The following link will allow you to submit requests to a test server.

https://andresamayadiaz.github.io/FrontAccountingSimpleAPI/


 
Title: Re: Project Announcement
Post by: John Spikowski on October 10, 2021, 05:28:46 pm
I had the opportunity to work with Acumatica and peek at their framework. It's a Microsoft monster and runs like a turtle. The package consists of C# generated .Net class DLLs which feeds .ASP for the web layer. Add IIS as the web server and it's another sad story of a company buying into Microsoft with no regard to multiple layers, bloatware or performance. Front Accounting is lightning fast, runs on everything using industry standard tools. (PHP / MySQL)

If resellers wanted to package and sell OS-ERP there is nothing stopping them from doing so. Creating extension is another way to monetize the direction. I really don't see Sage doing any more than maintaining Sage 100 with minor enhancement just to keep interest. Keep in mind the Business Basic programmer resource is getting thin with none of the younger programmers even considering looking at the language.

FA is a solid ERP that would be a good fit for most current 100 users. It would be a shame to let this opportunity pass and continue being forced fed the garbage being offered commercially. The hosting rip off is just salt on the wound.

If Sage partners / developers would commit to funding me to spend full time on the project I feel we could have a Sage 100 compatible solution all of us would benefit from. At this point I can only dedicate my spare time towards the project as like everyone one else I have bills to pay.
 
Fun Fact

OpenSAGE is a free, open source re-implementation of SAGE, the 3D .real-time strategy engine used in Command & Conquer Generals and other RTS titles from EA Pacific.

https://opensage.github.io/

Your cost for Sage Intacct will depend on the size of your accounting team and the modules you choose to implement. On average, our customers spend $15,000 to $35,000 on their annual subscription. Implementation typically costs one to one and a half times the amount of your annual subscription.

Please help me understand why a community driven open source ERP doesn't make sense.
Title: Re: Project Announcement
Post by: John Spikowski on October 15, 2021, 12:39:31 am
I feel the only way that this project is going to move forward on a consistent basis is if Sage partners sponsor the project. This has the potential of giving reseller status back to the business with an open source brand of their own. A community version would be available supported by the community on a peer basis. I will support sponsors bringing Open Sage ERP (or your branding) into your product line offering. This will include helping your team get up to speed with the framework and doing enhancements.

My open source contribution to the project will be facilitating the effort and promote a community involvement,

If you would like to sponsor this project by committing to a week of my time and become a provider, please send me an e-mail to support@opensage.org to chat more about the opportunity.
Title: Re: Project Announcement
Post by: John Spikowski on October 15, 2021, 08:11:57 pm
My suggestion is to install Front Accounting as a sub-directory off your current website or use XAMPP to run it on Windows and evaluate the software for yourself. If you feel like I do that it's a good foundation for the Open Sage ERP 100 work-a-like project, join the forum and let's hear your suggestions and opinions.

Title: Re: Project Announcement
Post by: John Spikowski on October 16, 2021, 10:00:15 pm
In this post I will try to clarify the direction of this project and its goals. Sage has been on mission to transform the 100 program into a cloud like product offering. The reseller program was eliminated and those selling the product were made partners / agents with a new commitment of revenue sharing from subscriptions as long as you meet quota and don't upset their customer. The subscription program direction is to eliminate outside sales and development resources and bring those services in-house. Sage punishes their loyal customers with crippled software and threats of no support if you don't get on board with their subscription program and buy the software again. My crystal ball tells me Sage will end of life their desktop offerings starting with 500 then 300 and finally 100 with a push to move those customers to Intacct or X3. I don't see their new Business Cloud (old Sage One) able to compete with QBO, ZERO or the handful of other like offerings. A reseller I know said it best. Working with Sage is like milking a dead cow.

Where does that leave Sage 100 customers and Partners? It's time to think about a disaster recovery plan and not die off with Sage's missteps and poor direction choices. The Open Sage ERP project is attempting to provide that safety net. This direction eliminates direct software costs by using open source software. Commercial accounting software is one the most expensive software investments being offered today with a glut of companies cashing in on the greed trend to keep this artificial cost prospering. Sage is notorious for monetizing every aspect of their business may it be documentation, developer resources and going to their sales meetings. Everything has a price tag.   

The Open Sage ERP project goals are to give Sage 100 partners their customers back and provide the direct service they once offered.  Sponsors will become the reseller network supporting their customers with software they can afford to use. Budgets can be used for implementation, training and support. I would like to dedicate my efforts to this project working with sponsors building a network of providers working together to archive a compatible 100 product that is web browser based. (self hosting or on premise) Sponsors will have their own sub-domain of OpenSage.org for demos and branding their direction with the product which I will host at no cost to the sponsor.

If this direction sounds like a viable plan, download the current version of Open Sage ERP (currently a mirror of FA) from the https://gitlab.com/open-sage/os-erp repository which I'm keeping current and evaluate for yourself if this project makes sense as the future of Sage 100.



   
Title: Re: Project Announcement
Post by: John Spikowski on October 22, 2021, 11:52:25 pm
There doesn't seem to be much interest in the project so far. I'm wondering if PHP is holding back BASIC developers from contributing. Good news, I have the ScriptBasic application server running as a proxy on Open Sage. This will allow extending the package with ScriptBasic rather than PHP. SciptBasic can use the HTML, CSS and JavaScript used in the core PHP code. ScriptBasic proxy server is 64 bit, multi-threaded and runs as a service. A major advantage ScriptBasic brings to the table is interfacing with C libraries is a breeze not so with PHP. Here are a few examples I put on the server.

MySQL
This example uses the C MySQL client extension module to access the items table in the Classic Models DB I plan to use for the demo company data. I also display the extension module functions that are available for more information about your connection.

MySQL - Items List (https://opensage.org/home/webmysql)

Code: Script BASIC
  1. ' MySQL Classic Models - Items
  2.  
  3. IMPORT cgi.bas
  4. IMPORT mysql.bas
  5.  
  6. dbh = mysql::RealConnect("localhost","os_admin","_JaR2oO0!","classicmodels")
  7. mysql::query(dbh,"SELECT * FROM products ORDER By productLine")
  8.  
  9.  
  10. cgi::Header 200,"text/html"
  11. cgi::FinishHeader
  12.  
  13. PRINT """
  14. <html>
  15. <header>
  16. <title>ScriptBasic MySQL Example</title>
  17. </header>
  18. <body>
  19. <table>
  20. <h1>Classic Models Items List</h1>
  21. <table style="width:60%">
  22.  <tr>
  23.    <th>Product Code</th>
  24.    <th>Product Line</th>
  25.    <th>Product Vendor</th>
  26.    <th>Product Name</th>
  27.    <th>In Stock</th>
  28.    <th>Cost</th>
  29.    <th>MSRP</th>
  30.  </tr>
  31. """
  32.  
  33. WHILE mysql::FetchHash(dbh,column)
  34.   PRINT "  <tr>\n"
  35.   PRINT "    <td>", column{"productCode"}, "</td>\n"
  36.   PRINT "    <td>", column{"productLine"}, "</td>\n"
  37.   PRINT "    <td>", column{"productVendor"}, "</td>\n"
  38.   PRINT "    <td>", column{"productName"}, "</td>\n"
  39.   PRINT "    <td align=\"right\">", column{"quantityInStock"}, "</td>\n"
  40.   PRINT "    <td align=\"right\">", FORMAT("%~$###.00~",column{"buyPrice"}), "</td>\n"
  41.   PRINT "    <td align=\"right\">", FORMAT("%~$###.00~",column{"MSRP"}), "</td>\n"
  42.   PRINT "  </tr>\n"
  43. WEND
  44.  
  45. PRINT """
  46. </table>
  47. <h1>MySQL Extension Module Functions</h1>
  48. """
  49. PRINT "<b>The database handle is: </b>",dbh,"<br>"
  50. PRINT "<b>Affected rows by SELECT: </b>",mysql::AffectedRows(dbh),"<br>\n"
  51. PRINT "<b>Character set name is: </b>",mysql::CharacterSetName(dbh),"<br>\n"
  52. PRINT "<b>Last error is: </b>",mysql::ErrorMessage(dbh),"<br>\n"
  53. PRINT "<b>Client info is: </b>",mysql::GetClientInfo(),"<br>\n"
  54. PRINT "<b>Host info is: </b>",mysql::GetHostInfo(dbh),"<br>\n"
  55. PRINT "<b>Proto info is: </b>",mysql::GetProtoInfo(dbh),"<br>\n"
  56. PRINT "<b>Server info is: </b>",mysql::GetServerInfo(dbh),"<br>\n"
  57. PRINT "<b>PING result: </b>",mysql::Ping(dbh),"<br>\n"
  58. PRINT "<b>Thread ID: </b>",mysql::ThreadId(dbh),"<br>\n"
  59. PRINT "<b>Status is: </b>",mysql::Stat(dbh),"<br>\n"
  60. PRINT """
  61. </body>
  62. </html>
  63. """
  64.  
  65. mysql::Close(dbh)
  66.  


cURL

This example uses the libcurl extension module to access the current weather in Anacortes WA where I live. The Open Weather API returns a JSON response. I'm using ScriptBasic's LIKE function to parse it for a formatted result.

Current Weather in Anacortes (https://opensage.org/home/web4cast)

Code: Script BASIC
  1. ' OpenWeather - Curl Example
  2.  
  3. IMPORT cgi.bas
  4. IMPORT curl.bas
  5.  
  6. FUNCTION MATCH(segment)
  7.   MATCH = JOKER(segment)
  8. END FUNCTION
  9.  
  10. place = "Anacortes,US"
  11.  
  12. ch = curl::init()
  13. curl::option(ch, "URL", "http://api.openweathermap.org/data/2.5/weather?q=" & place & "&units=imperial&appid=MYAPIKEY")
  14. curl::option(ch, "CUSTOMREQUEST", "GET")
  15. response = curl::perform(ch)
  16. curl::finish(ch)
  17.  
  18. cgi::Header 200,"text/html"
  19. cgi::FinishHeader
  20.  
  21. PRINT """
  22. <html>
  23. <body>
  24. """
  25.  
  26. PRINT "<h2>JSON Response</h2>\n"
  27. PRINT response, "<br><br>", "\n"
  28. PRINT "<h2>LIKE Parsed</h2>\n"
  29.  
  30. IF response LIKE "*lon\":*,\"lat\":*}*temp\":*,*pressure\":*,*humidity\":*}*dt\":*,*country\":\"*\"*timezone\":*,*name\":\"*\"*" THEN
  31.    PRINT "Country:    ", MATCH(13), "<br>\n"
  32.    PRINT "City:       ", MATCH(17), "<br>\n"
  33.    PRINT "Longitude:  ", MATCH(2), "<br>\n"
  34.    PRINT "Latitude:   ", MATCH(3), "<br>\n"
  35.    PRINT "Date/Time:  ", FORMATDATE("MM/DD/YEAR 0H:0m:0s", MATCH(11) + MATCH(15)), "<br>\n"
  36.    PRINT "Tempreture: ", MATCH(5), " F<br>\n"
  37.    PRINT "Pressure:   ", MATCH(7), " hPa<br>\n"
  38.    PRINT "Humidity:   ", MATCH(9), " %<br>\n"
  39. END IF
  40.  
  41. PRINT """
  42. </body>
  43. </html>
  44. """
  45.  

echo

This is a ScriptBasic script that echos back what is sent and displays the CGI parameters. This shows the functions that are available to your application when it receives a request.

CGI Echo Example (https://opensage.org/home/echo)

Code: Script BASIC
  1. ' CGI Echo
  2.  
  3. GLOBAL CONST nl = "\n"
  4. CONST NumberOfCookies = 3
  5.  
  6. INCLUDE cgi.bas
  7.  
  8. OPTION cgi$Method cgi::Get OR cgi::Post
  9.  
  10. cgi::Header 200,"text/html"
  11.  
  12. FOR i = 1 TO NumberOfCookies
  13.   ' cookie(i) is i, no domain is defined, path is /, expires after 10 seconds, not secure
  14.  cgi::SetCookie "cookie" & i, i, undef, "/", gmtime() + 10, false
  15. NEXT
  16.  
  17. cgi::FinishHeader
  18.  
  19. '-------------------------------------------------------
  20. PRINT """
  21. <HTML>
  22. <HEAD>
  23. <title>CGI Echo</title>
  24. </HEAD>
  25. <BODY><font face="VERDANA" size="2">
  26. <H1>View CGI Parameters</H1>
  27. This page shows the CGI parameters the way it was uploaded.
  28. <!-- here is the result of the previous HTTP request -->
  29. <FONT SIZE="3">
  30. <PRE>
  31. CGI system variables
  32. --------------------
  33.  
  34. """
  35.  
  36. PRINT "ServerSoftware  = ", cgi::ServerSoftware(), nl
  37. PRINT "ServerName      = ", cgi::ServerName(), nl
  38. PRINT "GatewayInterface= ", cgi::GatewayInterface(),nl
  39. PRINT "ServerProtocol  = ", cgi::ServerProtocol(), nl
  40. PRINT "ServerPort      = ", cgi::ServerPort(), nl
  41. PRINT "RequestMethod   = ", cgi::RequestMethod(), nl
  42. PRINT "PathInfo        = ", cgi::PathInfo(), nl
  43. PRINT "PathTranslated  = ", cgi::PathTranslated(), nl
  44. PRINT "ScriptName      = ", cgi::ScriptName(), nl
  45. PRINT "QueryString     = ", cgi::QueryString(), nl
  46. PRINT "RemoteHost      = ", cgi::RemoteHost(), nl
  47. PRINT "RemoteAddress   = ", cgi::RemoteAddress(), nl
  48. PRINT "AuthType        = ", cgi::AuthType(), nl
  49. PRINT "RemoteUser      = ", cgi::RemoteUser(), nl
  50. PRINT "RemoteIdent     = ", cgi::RemoteIdent(), nl
  51. PRINT "ContentType     = ", cgi::ContentType(), nl
  52. PRINT "ContentLength   = ", cgi::ContentLength(), nl
  53. PRINT "UserAgent       = ", cgi::UserAgent(), nl
  54. PRINT "Cookie          = ", cgi::RawCookie(), nl
  55.  
  56. PRINT "Referer         = ", cgi::Referer(), nl
  57. PRINT "Password        = ", Environ("HTTP_PASSWORD"), nl
  58. PRINT "Full auth string= ", Environ("HTTP_AUTHORIZATION"), nl
  59. PRINT "\nCookies:\n"
  60. FOR i = 1 TO NumberOfCookies
  61.   PRINT "cookie" & i, " ", cgi::Cookie("cookie" & i), "\n"
  62. NEXT
  63.  
  64. IF cgi::RequestMethod() = "GET" THEN
  65.   PRINT "GET text field using GetParam(\"TEXT-GET\") is ", cgi::GetParam("TEXT-GET"), nl
  66. END IF
  67.  
  68. IF cgi::RequestMethod() = "POST" THEN
  69.   PRINT "POST text field using PostParam(\"TEXT-POST\") is ", cgi::PostParam("TEXT-POST"), nl
  70. END IF
  71.  
  72. PRINT """
  73. </PRE>
  74. <TABLE>
  75.  <TR>
  76.    <TD BORDER=0 BGCOLOR="EEEEEE">
  77.      <PRE>
  78.      A simple form to POST parameters:<BR>
  79.      <FORM METHOD="POST" ACTION="/home/echo">
  80.        <INPUT TYPE="TEXT" VALUE="Default POST Field Text" NAME="TEXT-POST">
  81.        <INPUT TYPE="SUBMIT" NAME="SUBMIT-BUTTON" VALUE=" POST ">
  82.      </FORM>
  83.      </PRE>
  84.    </TD>
  85.    <TD BORDER=1 width="20">&nbsp;</TD>
  86.    <TD BORDER=0 BGCOLOR="EEEEEE">
  87.    <PRE>
  88.    A simple form to GET parameters:<BR>
  89.    <FORM METHOD="GET" ACTION="/home/echo">
  90.      <INPUT TYPE="TEXT" VALUE="Default GET Field Text" NAME="TEXT-GET">
  91.      <INPUT TYPE="SUBMIT" NAME="SUBMIT-BUTTON" VALUE=" GET ">
  92.    </FORM>
  93.  
  94.    </TD>
  95.  </TR>
  96. </TABLE>
  97. </BODY>
  98. </HTML>
  99. """
  100.  


Title: Re: Project Announcement
Post by: John Spikowski on October 23, 2021, 11:57:36 pm
I wanted to make sure AJAX was going to work with the ScriptBasic application proxy server. I'm happy to say it works really well. This example list the Classic Models Items  based on the Product Line you chose.

ScriptBasic AJAX Example (https://opensage.org/home/sbajax)

sbajax (This could have been a HTML or PHP script - I wanted to run everything on the proxy server)
Code: Script BASIC
  1. ' ScriptBasic AJAX & MySQL
  2.  
  3. IMPORT cgi.bas
  4.  
  5. OPTION cgi$Method cgi::Get OR cgi::Post
  6.  
  7. cgi::Header 200,"text/html"
  8. cgi::FinishHeader
  9.  
  10. PRINT """
  11. <html>
  12. <head>
  13. <script>
  14. function showItems(str) {
  15.  if (str == "") {
  16.    document.getElementById("results").innerHTML = "";
  17.    return;
  18.  } else {
  19.    var xmlhttp = new XMLHttpRequest();
  20.    xmlhttp.onreadystatechange = function() {
  21.      if (this.readyState == 4 && this.status == 200) {
  22.        document.getElementById("results").innerHTML = this.responseText;
  23.      }
  24.    };
  25.    xmlhttp.open("GET","/home/getitems.sb?q="+str,true);
  26.    xmlhttp.send();
  27.  }
  28. }
  29. </script>
  30. </head>
  31. <body>
  32.  
  33. <form>
  34.  <select name="items" onchange="showItems(this.value)">
  35.    <option value="">Product Line</option>
  36.    <option value="Classic Cars">Classic Cars</option>
  37.    <option value="Motorcycles">Motorcycles</option>
  38.    <option value="Planes">Planes</option>
  39.    <option value="Ships">Ships</option>
  40.    <option value="Trains">Trains</option>
  41.    <option value="Trucks and Buses">Trucks and Buses</option>
  42.    <option value="Vintage Cars">Vintage Cars</option>
  43.  </select>
  44. </form>
  45. <br>
  46. <div id="results"></div>
  47.  
  48. </body>
  49. </html>
  50. """
  51.  

getitems.sb
Code: Script BASIC
  1. ' AJAX - getitems.sb
  2.  
  3. IMPORT cgi.bas
  4. IMPORT mysql.bas
  5.  
  6. cgi::Header 200,"text/html"
  7.  
  8. PRINT """
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <style>
  13. table {
  14.  width: 100%;
  15.  border-collapse: collapse;
  16. }
  17.  
  18. table, td, th {
  19.  border: 1px solid black;
  20.  padding: 5px;
  21. }
  22.  
  23. th {text-align: left;}
  24. </style>
  25. </head>
  26. <body>
  27. """
  28.  
  29. product_line = cgi::GetParam("q")
  30.  
  31. dbh = mysql::RealConnect("localhost","USERID","PASSWORD","classicmodels")
  32. mysql::query(dbh,"SELECT * FROM products WHERE productLine = '" & product_line & "'")
  33.  
  34. PRINT """
  35. <table>
  36.  <tr>
  37.    <th>Product Code</th>
  38.    <th>Product Line</th>
  39.    <th>Product Vendor</th>
  40.    <th>Product Name</th>
  41.    <th>In Stock</th>
  42.    <th>Cost</th>
  43.    <th>MSRP</th>
  44.  </tr>
  45. """
  46.  
  47. WHILE mysql::FetchHash(dbh,column)
  48.   PRINT "  <tr>\n"
  49.   PRINT "    <td>", column{"productCode"}, "</td>\n"
  50.   PRINT "    <td>", column{"productLine"}, "</td>\n"
  51.   PRINT "    <td>", column{"productVendor"}, "</td>\n"
  52.   PRINT "    <td>", column{"productName"}, "</td>\n"
  53.   PRINT "    <td align=\"right\">", column{"quantityInStock"}, "</td>\n"
  54.   PRINT "    <td align=\"right\">", FORMAT("%~$###.00~",column{"buyPrice"}), "</td>\n"
  55.   PRINT "    <td align=\"right\">", FORMAT("%~$###.00~",column{"MSRP"}), "</td>\n"
  56.   PRINT "  </tr>\n"
  57. WEND
  58.  
  59. PRINT """
  60. </table>
  61. </body>
  62. </html>
  63. """
  64.  
  65. mysql::Close(dbh)
  66.  


Title: Re: Project Announcement
Post by: John Spikowski on October 25, 2021, 12:31:41 am
This AJAX example of a login form with length validation uses a HTML, JS, CSS and ScriptBasic file for the AJAX processing. Once the Login Submit is clicked it runs the sbajax example I posted previously. I modified the sbajax script to allow both GET and POST requests.

ScriptBasic AJAX Login Example (https://opensage.org/test/index.html)

index.html
Code: HTML
  1. <!DOCTYPE html>
  2. <link href="style.css" rel="stylesheet" type="text/css">
  3. <script src="script.js"></script>
  4. </head>
  5. <div id="mainform">
  6. <div class="innerdiv">
  7. <form action='/home/sbajax' id="myForm" method='post' name="myForm">
  8. <center><img src='forum_logo.png' alt='Open Sage' border='0' ></center>
  9. <tr>
  10. <td>User Name</td>
  11. <td><input id='username1' name='username' onblur="validate('username', this.value)" type='text'></td>
  12. <td>
  13. <div id='username'></div>
  14. </td>
  15. </tr>
  16. <tr>
  17. <td>Password</td>
  18. <td><input id='password1' name='password' onblur="validate('password', this.value)" type='password'></td>
  19. <td>
  20. <div id='password'></div>
  21. </td>
  22. </tr>
  23. <input onclick="checkForm()" type='button' value='Login Submit'>
  24. </form>
  25. </div>
  26. </body>
  27. </html>
  28.  

style.css
Code: CSS
  1. @import "http://fonts.googleapis.com/css?family=Fauna+One|Muli";
  2. #mainform{
  3. width:960px;
  4. margin:20px auto;
  5. padding-top:20px;
  6. font-family:'Fauna One',serif
  7. }
  8. .innerdiv{
  9. width:65%;
  10. float:left
  11. }
  12. form{
  13. background-color:#fff;
  14. color:#123456;
  15. box-shadow:0 1px 1px 1px gray;
  16. width:500px;
  17. margin:50px 250px 0 50px;
  18. float:left;
  19. height:300px;
  20. padding:10px
  21. }
  22. input{
  23. width:250px;
  24. height:30px;
  25. margin-top:10px;
  26. border-radius:3px;
  27. padding:2px;
  28. box-shadow:0 1px 1px 0 #a9a9a9;
  29. margin:10px
  30. }
  31. input[type=button]{
  32. background-color:#8FBC8B;
  33. border:1px solid #fff;
  34. font-family:'Fauna One',serif;
  35. font-weight:700;
  36. font-size:18px;
  37. color:#fff;
  38. width:50%;
  39. margin-left:125px;
  40. margin-top:30px
  41. }
  42. span{
  43. color:green
  44. }
  45. #myForm div{
  46. color:red;
  47. font-size:14px
  48. }
  49.  

script.js
Code: Javascript
  1. function checkForm() {
  2. // Fetching values from all input fields and storing them in variables.
  3. var name = document.getElementById("username1").value;
  4. var password = document.getElementById("password1").value;
  5. //Check input Fields Should not be blanks.
  6. if (name == '' || password == '') {
  7. alert("Fill All Fields");
  8. } else {
  9. //Notifying error fields
  10. var username1 = document.getElementById("username");
  11. var password1 = document.getElementById("password");
  12. //Check All Values/Informations Filled by User are Valid Or Not.If All Fields Are invalid Then Generate alert.
  13. if (username1.innerHTML == 'Must be 3+ letters' || password1.innerHTML == 'Password too short') {
  14. alert("Fill Valid Information");
  15. } else {
  16. //Submit Form When All values are valid and run sbajax.
  17. document.getElementById("myForm").submit();
  18. }
  19. }
  20. }
  21. // AJAX code to check input field values when onblur event triggerd.
  22. function validate(field, query) {
  23. var xmlhttp;
  24. if (window.XMLHttpRequest) { // for IE7+, Firefox, Chrome, Opera, Safari
  25. xmlhttp = new XMLHttpRequest();
  26. } else { // for IE6, IE5
  27. xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  28. }
  29. xmlhttp.onreadystatechange = function() {
  30. if (xmlhttp.readyState != 4 && xmlhttp.status == 200) {
  31. document.getElementById(field).innerHTML = "Validating..";
  32. } else if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
  33. document.getElementById(field).innerHTML = xmlhttp.responseText;
  34. } else {
  35. document.getElementById(field).innerHTML = "";
  36. }
  37. }
  38. xmlhttp.open("GET", "/home/validation.sb?field=" + field + "&query=" + query, false);
  39. xmlhttp.send();
  40. }
  41.  

validation.sb
Code: Script BASIC
  1. ' ScriptBasic AJAX Validation
  2.  
  3. IMPORT cgi.bas
  4.  
  5. cgi::Header 200,"text/html"
  6.  
  7. PRINT """
  8. <!DOCTYPE html>
  9. <html>
  10. <body>
  11. """
  12. value = cgi::GetParam("query")
  13. formfield = cgi::GetParam("field")
  14.  
  15. ' Check length of username for greater than 3 characters
  16.  
  17. IF formfield = "username" THEN
  18.   IF LEN(value) < 4 THEN
  19.     PRINT "Must be 3+ letters"
  20.   ELSE
  21.     PRINT "<span>Valid</span>"
  22.   END IF
  23. END IF
  24.  
  25. ' Check length of password for greater than 5 characters
  26.  
  27. IF formfield = "password" THEN
  28.   IF LEN(value) < 6 THEN
  29.     PRINT "Password too short"
  30.   ELSE
  31.     PRINT "<span>Strong</span>"
  32.   END IF
  33. END IF
  34.  
  35. PRINT """
  36. </body>
  37. </html>
  38. """
  39.  
Title: Re: Project Announcement
Post by: John Spikowski on October 26, 2021, 08:49:55 pm
One feature Sage 100 offers with customizer is to add new fields (UDF) and tables (UDT). OS-ERP offers a similar feature and done with extensions. This extension (showing customer added fields only - hooks contains the code for the complete extension) is an example of how to extend a data entry screen. This allows extending OS-ERP but still have a default release candidate. Like 100, extensions are enabled by company and role.

Original Customer Maintenance

(https://opensage.org/test/customer_default.png)
 
Customer - Added Fields

(https://opensage.org/test/customer_udf.png)


Add_Customers.php
Code: PHP
  1. <?php
  2. /**********************************************************************
  3.     Copyright (C) FrontAccounting, LLC.
  4.         Released under the terms of the GNU General Public License, GPL,
  5.         as published by the Free Software Foundation, either version 3
  6.         of the License, or (at your option) any later version.
  7.     This program is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10.     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
  11. ***********************************************************************/
  12. $page_security = 'SA_CUSTOMER';
  13. $path_to_root = "../../..";
  14.  
  15. include_once($path_to_root . "/includes/db_pager.inc");
  16. include_once($path_to_root . "/includes/session.inc");
  17. $js = "";
  18. if (user_use_date_picker())
  19.         $js .= get_js_date_picker();
  20.        
  21. page(_($help_context = "Customer Additional Information"), false, false, "", $js);
  22.  
  23. include_once($path_to_root . "/includes/date_functions.inc");
  24. include_once($path_to_root . "/includes/banking.inc");
  25. include_once($path_to_root . "/includes/ui.inc");
  26. include_once($path_to_root . "/includes/ui/contacts_view.inc");
  27. include_once($path_to_root . "/modules/additional_fields/includes/ui/additional_cust_info_ui.inc");
  28. include_once($path_to_root . "/sales/includes/db/customers_db.inc");
  29. include_once($path_to_root . "/sales/includes/db/credit_status_db.inc");
  30. include_once($path_to_root . "/modules/additional_fields/includes/addfields_db.inc");
  31.  
  32. if (isset($_GET['debtor_no']))
  33. {
  34.         $_POST['customer_id'] = $_GET['debtor_no'];
  35. }
  36.  
  37. $selected_id = get_post('customer_id','');
  38. //--------------------------------------------------------------------------------------------
  39.  
  40. function customer_settings($selected_id)
  41. {
  42.         global $page_nested;
  43.        
  44.         if ($selected_id)
  45.         {
  46.                 $myrow = get_customer($selected_id);
  47.  
  48.                 $_POST['CustName'] = $myrow["name"];
  49.                 $_POST['cust_ref'] = $myrow["debtor_ref"];
  50.                 $_POST['address']  = $myrow["address"];
  51.                 $_POST['tax_id']  = $myrow["tax_id"];
  52.                 $_POST['sales_type'] = $myrow["sales_type"];
  53.                 $_POST['curr_code']  = $myrow["curr_code"];
  54.                 $_POST['credit_status']  = $myrow["credit_status"];
  55.                 $_POST['payment_terms']  = $myrow["payment_terms"];
  56.                 $_POST['discount']  = percent_format($myrow["discount"] * 100);
  57.                 $_POST['pymt_discount']  = percent_format($myrow["pymt_discount"] * 100);
  58.                 $_POST['credit_limit']  = price_format($myrow["credit_limit"]);
  59.                 $_POST['notes']  = $myrow["notes"];
  60.                 $_POST['inactive'] = $myrow["inactive"];
  61.  
  62.                 $myrow2 = get_customer_additional_info($selected_id);
  63.                 $_POST['customer_id'] = $myrow2["cust_debtor_no"];
  64.                 $_POST['cust_city']  = $myrow2["cust_city"];
  65.                 $_POST['cust_department']  = $myrow2["cust_department"];
  66.                 $_POST['cust_country']  = $myrow2["cust_country"];
  67.                 $_POST['cust_postcode']  = $myrow2["cust_postcode"];
  68.                 $_POST['cust_doc_type']  = $myrow2["cust_doc_type"];
  69.                 $_POST['cust_valid_digit']  = $myrow2["cust_valid_digit"];
  70.                 $_POST['cust_start_date']  = sql2date($myrow2["cust_start_date"]);
  71.                 $_POST['cust_sector']  = $myrow2["cust_sector"];
  72.                 $_POST['cust_class']  = $myrow2["cust_class"];
  73.                 $_POST['cust_custom_one']  = $myrow2["cust_custom_one"];
  74.                 $_POST['cust_custom_two']  = $myrow2["cust_custom_two"];
  75.                 $_POST['cust_custom_three']  = $myrow2["cust_custom_three"];
  76.                 $_POST['cust_custom_four']  = $myrow2["cust_custom_four"];
  77.  
  78.         }
  79.  
  80.         start_outer_table(TABLESTYLE2);
  81.  
  82.         table_section(1);
  83.  
  84.         table_section_title(_("Name and Address"));
  85.  
  86.         label_row(_("Customer Name:"),$_POST['CustName']);
  87.         label_row(_("Customer Short Name:"),$_POST['cust_ref']);
  88.         readonly_textarea_row(_("Address:<br>\n(Read Only)"), 'address', $_POST['address'], 35, 5);
  89.         city_list_row(_("City:"), 'cust_city', null, false, _("Select City"));
  90.         departments_list_row(_("State/Department:"), 'cust_department', null, false, _("Select Department"));
  91.         country_list_row(_("Country:"), 'cust_country', null, false, _("Select Country"));
  92.         text_row(_("Postcode:"), 'cust_postcode', null, 10, 10);
  93.         label_row(_("GSTNo:"),$_POST['tax_id']);
  94.         text_row(_("Validation Digit:"), 'cust_valid_digit', null, 1, 1);
  95.         document_types_list_row(_("Type of Document:"), 'cust_doc_type', null, false, _("Select Document Type"));
  96.         customer_class_list_row(_("Customer Class:"), 'cust_class', null, false, _("Select Class"));
  97.         $currency_name = get_currency($myrow["curr_code"]);
  98.         label_row(_("New Customer's Currency:"), $currency_name['currency']);
  99.         $sales_type_name = get_sales_type_name($myrow["sales_type"]);
  100.         label_row(_("Sales Type/Price List:"), $sales_type_name);
  101.         date_row(_("Customer Since") . ":", 'cust_start_date', '', true);
  102.         label_row(_("Customer Status:"),($myrow['inactive']==1 ? _("Inactive") : _("Active")), -1);
  103.  
  104.         table_section(2);
  105.  
  106.         table_section_title(_("Sales"));
  107.         label_row(_("Discount Percent:"),$_POST['discount']);
  108.         label_row(_("Prompt Payment Discount Percent:"),$_POST['pymt_discount']);
  109.         label_row(_("Credit Limit:"),$_POST['credit_limit']);
  110.         $payment_terms_name = get_payment_terms($myrow["payment_terms"]);
  111.         label_row(_("Payment Terms:"), $payment_terms_name['terms']);
  112.         $credit_status_name = get_credit_status($myrow["credit_status"]);
  113.         label_row(_("New Credit Status:"), $credit_status_name['reason_description']);
  114.         readonly_textarea_row(_("General Notes: (Read Only)"), 'notes', null, 35, 5);
  115.  
  116.         table_section_title(_("Additional Information"));
  117.  
  118.         text_row(get_cust_custom_labels_name(1).':', 'cust_custom_one', null, 40, 255);
  119.         text_row(get_cust_custom_labels_name(2).':', 'cust_custom_two', null, 40, 255);
  120.         text_row(get_cust_custom_labels_name(3).':', 'cust_custom_three', null, 40, 255);
  121.         text_row(get_cust_custom_labels_name(4).':', 'cust_custom_four', null, 40, 255);
  122.         sectors_list_row(_("Sector:"), 'cust_sector', null, false, _("Select Sector"));
  123.        
  124.         end_outer_table(1);
  125.  
  126.         div_start('controls');
  127.        
  128.         if (!$selected_id)
  129.         {
  130.                 display_heading(_('Select a Customer'));
  131.         }
  132.         else
  133.         {
  134.                 submit_center_first('submit', _("Update Customer and Additional Infomation"),
  135.                   _('Update customer data and Additional Infomation'), $page_nested ? true : 'default');
  136.                 submit_center_last('delete', _("Delete Customer Additional Information"),
  137.                   _('Delete customer and Additional Infomation data'), true);
  138.         }
  139.         div_end();
  140. }
  141.  
  142. if (isset($_POST['submit']))
  143. {
  144.  
  145.         if ($selected_id)
  146.         {
  147.                 $add_cust_info_exists = db_query("SELECT cust_debtor_no FROM ".TB_PREF."addfields_cust where cust_debtor_no = '$selected_id' LIMIT 1");
  148.                 if(db_fetch($add_cust_info_exists))
  149.                         {
  150.                         update_customer_additional_info($_POST['customer_id'],
  151.                         $_POST['cust_city'], $_POST['cust_department'],
  152.                                 $_POST['cust_country'], $_POST['cust_postcode'],
  153.                                 $_POST['cust_doc_type'], $_POST['cust_valid_digit'],
  154.                                 $_POST['cust_start_date'], $_POST['cust_sector'],
  155.                                 $_POST['cust_class'], $_POST['cust_custom_one'],
  156.                                 $_POST['cust_custom_two'], $_POST['cust_custom_three'],
  157.                                 $_POST['cust_custom_four']);
  158.                     }
  159.                     else
  160.                     {
  161.                         add_customer_additional_info($_POST['customer_id'],
  162.                         $_POST['cust_city'], $_POST['cust_department'],
  163.                                 $_POST['cust_country'], $_POST['cust_postcode'],
  164.                                 $_POST['cust_doc_type'], $_POST['cust_valid_digit'],
  165.                                 $_POST['cust_start_date'], $_POST['cust_sector'],
  166.                                 $_POST['cust_class'], $_POST['cust_custom_one'],
  167.                                 $_POST['cust_custom_two'], $_POST['cust_custom_three'],
  168.                                 $_POST['cust_custom_four']);
  169.                     }
  170.  
  171.                 $Ajax->activate('customer_id'); // in case of status change
  172.                 display_notification(_("Customer additional information has been updated."));
  173.         }
  174. }
  175. elseif (isset($_POST['delete']))
  176. {
  177.                 delete_customer_additional_info($selected_id);
  178.                 display_notification(_("Selected Customer Additional Infomation has been deleted."));
  179.                 $Ajax->activate('_page_body');
  180. }
  181. //--------------------------------------------------------------------------------------------
  182.  
  183. start_form();
  184.  
  185. if (db_has_customers())
  186. {
  187.         start_table(TABLESTYLE_NOBORDER);
  188.         start_row();
  189.         customer_list_cells(_("Select a customer: "), 'customer_id', null, _('Select a customer'), true, check_value('show_inactive'));
  190.         check_cells(_("Show inactive:"), 'show_inactive', null, true);
  191.         end_row();
  192.         end_table();
  193.  
  194.         if (get_post('_show_inactive_update')) {
  195.                 $Ajax->activate('customer_id');
  196.                 set_focus('customer_id');
  197.         }
  198. }
  199. else
  200. {
  201.         hidden('customer_id');
  202. }
  203. if ($selected_id)
  204.         customer_settings($selected_id);
  205.  
  206. end_form();
  207. end_page();
  208.  

Hooks.php
Code: PHP
  1. <?php
  2. /**********************************************************************
  3.         Released under the terms of the GNU General Public License, GPL,
  4.         as published by the Free Software Foundation, either version 3
  5.         of the License, or (at your option) any later version.
  6.         This program is distributed in the hope that it will be useful,
  7.         but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  9.         See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
  10.  
  11.         ================================================================
  12.         Front Additional Fields
  13.         ================================================================
  14.        
  15. ***********************************************************************/
  16.  
  17. define ('SS_ADDFLD_C', 141<<8);
  18. define ('SS_ADDFLD', 142<<8);
  19. define ('SS_ADDFLD_A', 143<<8);
  20.  
  21. class additional_fields_app extends application {
  22.        
  23.         function __construct() {
  24.                
  25.                 parent::__construct('AddFields', _($this->help_context = 'Additional Fields'));
  26.  
  27.                 $this->add_module(_("Customer Additional Information"));
  28.                 $this->add_lapp_function(0, _("Additional &Customer Information"),
  29.                         "/modules/additional_fields/manage/add_customers.php?", 'SA_CUSTOMER', MENU_ENTRY);
  30.                 $this->add_rapp_function(0, _('Customer Custom Field Labels'),
  31.                         '/modules/additional_fields/manage/cust_customer_labels.php?', 'SA_ADD_FIELDS_CUST_LABELS', MENU_MAINTENANCE);
  32.  
  33.                 $this->add_module(_("Supplier Additional Information"));
  34.                 $this->add_lapp_function(1, _("Additional &Supplier Information"),
  35.                         "/modules/additional_fields/manage/add_suppliers.php?", 'SA_SUPPLIER', MENU_ENTRY);
  36.                 $this->add_rapp_function(1, _('Supplier Custom Field Labels'),
  37.                         '/modules/additional_fields/manage/cust_supplier_labels.php?', 'SA_ADD_FIELDS_SUPP_LABELS', MENU_MAINTENANCE);
  38.  
  39.                 $this->add_module(_("Item Additional Information"));
  40.                 $this->add_lapp_function(2, _("Additional &Item Information"),
  41.                         "/modules/additional_fields/manage/add_items.php?", 'SA_ITEM', MENU_ENTRY);
  42.                 $this->add_rapp_function(2, _('Item Custom Field Labels'),
  43.                         '/modules/additional_fields/manage/cust_item_labels.php?', 'SA_ADD_FIELDS_ITEM_LABELS', MENU_MAINTENANCE);
  44.  
  45.                 $this->add_module(_('Maintenance'));
  46.                 $this->add_lapp_function(3, _('Manage Document Types'),
  47.                         '/modules/additional_fields/manage/document_types.php?', 'SA_ADD_FIELDS_DOC_TYPES', MENU_MAINTENANCE);
  48.                 $this->add_lapp_function(3, _('Manage Beneficiary Classes'),
  49.                         '/modules/additional_fields/manage/customer_class.php?', 'SA_ADD_FIELDS_BEN_CLASSES', MENU_MAINTENANCE);
  50.                 $this->add_lapp_function(3, _('Manage Sectors'),
  51.                         '/modules/additional_fields/manage/sectors_add_info.php?', 'SA_ADD_FIELDS_SECTOR', MENU_MAINTENANCE);
  52.                 $this->add_rapp_function(3, _('Manage Countries'),
  53.                         '/modules/additional_fields/manage/country.php?', 'SA_ADD_FIELDS_COUNTRY', MENU_MAINTENANCE);
  54.                 $this->add_rapp_function(3, _('Manage Departments'),
  55.                         '/modules/additional_fields/manage/department_add_info.php?', 'SA_ADD_FIELDS_DEPARTMENT', MENU_MAINTENANCE);
  56.                 $this->add_rapp_function(3, _('Manage Cities'),
  57.                         '/modules/additional_fields/manage/city_add_info.php?', 'SA_ADD_FIELDS_CITY', MENU_MAINTENANCE);
  58.                 $this->add_extensions();
  59.         }
  60.        
  61. }
  62.  
  63. class hooks_additional_fields extends hooks {
  64.  
  65.         function __construct() {
  66.                 $this->module_name = 'additional_fields';
  67.         }
  68.        
  69.         function install_tabs($app) {
  70.                 $app->add_application(new additional_fields_app);
  71.         }
  72.        
  73.         function install_access() {
  74.                 $security_sections[SS_ADDFLD_C] =  _("Additional Fields Configuration");
  75.                 $security_sections[SS_ADDFLD] =  _("Additional Fields Transactions");
  76.                 $security_sections[SS_ADDFLD_A] =  _("Additional Fields Analytics");
  77.                 $security_areas['SA_ADD_FIELDS_SECTOR'] = array(SS_ADDFLD_C|101, _("AddFields Sector"));
  78.                 $security_areas['SA_ADD_FIELDS_COUNTRY'] = array(SS_ADDFLD_C|102, _("AddFields Country"));
  79.                 $security_areas['SA_ADD_FIELDS_CITY'] = array(SS_ADDFLD_C|103, _("AddFields City"));
  80.                 $security_areas['SA_ADD_FIELDS_DEPARTMENT'] = array(SS_ADDFLD_C|104, _("AddFields Departments"));
  81.                 $security_areas['SA_ADD_FIELDS_BEN_CLASSES'] = array(SS_ADDFLD_C|105, _("AddFields Beneficiary Classes"));
  82.                 $security_areas['SA_ADD_FIELDS_DOC_TYPES'] = array(SS_ADDFLD_C|106, _("AddFields Document Types"));
  83.                 $security_areas['SA_ADD_FIELDS_ITEM_LABELS'] = array(SS_ADDFLD_C|107, _("AddFields Item Custom Field Labels"));
  84.                 $security_areas['SA_ADD_FIELDS_SUPP_LABELS'] = array(SS_ADDFLD_C|108, _("AddFields Supplier Custom Field Labels"));
  85.                 $security_areas['SA_ADD_FIELDS_CUST_LABELS'] = array(SS_ADDFLD_C|109, _("AddFields Customer Custom Field Labels"));
  86.                 return array($security_areas, $security_sections);
  87.         }
  88.  
  89.         function activate_extension($company, $check_only=true) {
  90.                 global $db_connections;
  91.                
  92.                 $updates = array( 'update.sql' => array('frontadd'));
  93.  
  94.                 return $this->update_databases($company, $updates, $check_only);
  95.         }
  96.        
  97.         function deactivate_extension($company, $check_only=true) {
  98.                 global $db_connections;
  99.  
  100.                 $updates = array('remove.sql' => array('frontadd'));
  101.  
  102.                 return $this->update_databases($company, $updates, $check_only);
  103.         }
  104.  
  105. }
  106.  
Title: Re: Project Announcement
Post by: John Spikowski on October 28, 2021, 02:05:03 am
I thought I would install OS-ERP (FA) on my main Windows 10 development laptop as it has a static IP on my fiber connection. XAMPP now offers a PHP 8.0.12 version of the install. FA hasn't officially recommended PHP 8 yet and suggests using PHP 7 instead. I decided to try PHP 8 and see if it breaks anything. After getting everything installed I noticed the dashboard graphics weren't working. It seems XAMPP has disabled the GD extension in the php.ini file. Once I enabled the GD extension the graphics worked. So far everything else seems normal. If you plan to try OS-ERP from the OS-ERP Repository (https://gitlab.com/open-sage/os-erp) I suggest using the XAMPP PHP 7 latest install until the developers give the green light on PHP 8.

I've started on the first OS-ERP specific change which is making Customer Maintenance look more like 100. I'm going to be moving fields from the Additional tab to the main screen. I'm also going to create separate addresses fields rather than using a multi-line text box.
Title: Re: Project Announcement
Post by: John Spikowski on December 07, 2021, 11:30:35 pm
The OS-ERP version is now at 2.4.11.

I'm working on building a demo company using the MySQL example company Classic Models.

I'm splitting up my open source activities between OS-ERP and the new HTML extension module that will allow substituting NOMADS for a browser interface.
Title: Re: Project Announcement
Post by: John Spikowski on March 06, 2022, 03:57:44 pm
Quote
Congratulations! FrontAccounting has just been recognized with the following awards by SourceForge:
  • Community Leader
  • Community Choice
  • Open Source Excellence
  • SourceForge Favorite

These honors are awarded only to select projects that have reached significant milestones in terms of downloads and user engagement from the SourceForge community.

This is a big achievement, as your project has qualified for these awards out of over 500,000 open source projects on SourceForge. SourceForge sees nearly 30 million users per month looking for, and developing, open source software.

The Open Sage ERP offering is a fork of the FrontAccounting project. I have rebranded it and have maintain a repository (https://gitlab.com/open-sage/os-erp) updating it with fixes and enhancements from the FA project.

I have install OS-ERP on the Open Sage site if you would like to give it a review and see if it would meet your needs. (I'm still working on building a demo company so feel free to experiment.)

Open Sage ERP Community Demo Install (https://opensage.org/oserp)

User Name: demo
Password: demo

This is a community effort like Sage City but no subscriptions or partner fees to pay. OS-ERP is written in PHP which is the most popular scripting language on the planet. The OS-ERP framework is very well done and easy to expand on. Please join the forum and contribute to the project with the skills you have to offer. (accounting, programming, web site expansion, ...)
Title: Re: Project Announcement
Post by: John Spikowski on March 20, 2022, 12:12:57 pm
I'm working on building a demo company using the MySQL Classic Models DB. I have the inventory built. I've attached the Inventory Stock Check Report that will show the items inventory. I was able to get the Supplier (vendor) initial records build. The attached Supplier Trial Balances report that shows the vendors being used in this demo company.

I found a few sites that have pictures of these models which I plan to incorporate with the inventory items.

I setup a Shopify developer sandbox which will use the same inventory. The goal is a seamless integration.

If you would like to help move this along send me an email.
 
Title: Re: Project Announcement
Post by: John Spikowski on March 24, 2022, 12:45:11 am
I have Customers added to the demo company. The MySQL DB contains invoices and payments but no purchases. I'm going to try and generate some sales orders next.