Error Purchasing Requisition in Microsoft Dynamics GP

Microsoft Dynamics GPI’ve been working with a client to create a new standalone Microsoft Dynamics GP test system. We copied the databases to the new SQL Server and were progressing through several tasks making sure everything was aligned and working correctly as they have a number of add-ins which needed to be installed.

One user testing the purchasing module encountered an error when trying to transfer a purchase requisition to purchase order:

Error produced when purchasing a purchase requisition

The request failed with HTTP status 404: Not Found.

The error was produced because the details for the Reporting Services Reports in Reporting Tools Setup had not been updated and the reports deployed; the links were still to the live server SSRS implementation which was inaccessible to the new sandboxed test environment.

Once the links were updated and redeployed the error went away.

Microsoft Dynamics GP 2016 Now Out of Mainstream Support

Microsoft Dynamics GPA couple of days ago, I posted about the updated Microsoft Dynamics GP roadmap which goes through 2028. One item which is worth noting, is that Microsoft Dynamics GP 2016 RTM and 2016 R2 are both out of mainstream support as of yesterday and those versions are now in extended support.

This means that critical security issues found will be fixed, but no feature enhancements or other bugs will be added or fixed. This does of course include changes to the VAT Daybook module which are very important to users in the UK with the ever changing requirements from HMRC for MTD.

If you are using Dynamics GP 2016, I would recommend contacting your partner to discuss an upgrade to a version under mainstream support. If you are in the UK it is important you do this as you will only get updates to the MTD functionality if you are on the latest build of Microsoft Dynamics GP and under the Modern Lifecycle policy.

For those clients with MTD requirements, but who, for whatever reason cannot upgrade at the moment, ISC have an add-on available for all versions of Microsoft Dynamics GP which will support the MTD submissions to HMRC. If you’d like to discuss requirements in this area, please use the contact form below.

Microsoft Dynamics GP Roadmap to 2028 and Beyond

Microsoft Dynamics GPTerry Heley on the Dynamics GP Support and Services Blog posted an article on Friday on the exciting future of Microsoft Dynamics GP and giving a Lifecycle Update. As part of the article she inked to the published Lifecycle (Roadmap) for Microsoft Dynamics GP which extends to 2028 and beyond for Microsoft Dynamics GP.

The published roadmap also shows the end of mainstream and extended support for versions older versions of the product which predate the Modern Lifecycle:

Microsoft Dynamics GP Roadmap through to 2028

In brief:

  • 2013 and 2013 R2 are out of mainstream support and in extended support until 11/4/2023.
  • 2015 and 2015 R2 are out of mainstream support and in extended support until 14/4/2025.
  • 2016 and 2016 R2 are out of mainstream support on 13/7/2021 and in extended support until 7/4/2026.
  • 2018 and 2018 R2 in mainstream support until 10/1/2023 and in extended support until 7/4/2026.

Microsoft Dynamics GP is now under the Modern Lifecycle and has the same commitment from Microsoft as Dynamics 365. The Modern Lifecycle means there should be more frequent updates to Microsoft Dynamics GP with at least three updates a year in January, June/July and October.

Microsoft will continue to keep adding new features and improving it based on direct feedback from users. The best way to make sure you continue to benefit from the improvements is to keep up-to-date on upgrades and use the latest version of Microsoft Dynamics GP.

The key takeaway from the published Lifecycle is that Microsoft Dynamics GP is not going anywhere and development will continue under the Modern Lifecycle policy with multiple releases each year.

ClassicPress Plugin Development: Load Options with Defaults

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

In the last post I covered saving and loading options in a ClassicPress plugin. When you create a plugin with options you will want to provide defaults to be used before the user makes any changes to the settings; this both allows for basic operation of the plugin and avoids unset option errors.

The get_option function does allow for defaults to be passed, but this will only work if there are no options; it will not work effectively if new options are added to the plugin. This can be handled using the wp_parse_args function which merges user defined arguments into defaults array.

wp_parse_args( string|array|object $args, array $defaults = array() )

Parameters

$args (string|array|object) (Required) Value to merge with $defaults. $defaults (array) (Optional) Array that serves as the defaults. Default value: array()

Return

(array) Merged user defined values with defaults.

The below is an example of loading options with defaults from my Comment Validator plugin:

/**
 * Get options including defaults.
 *
 * @since 1.2.0
 *
 */
function azrcrv_cv_get_option($option_name){
 
	$defaults = array(
						'min_length' => 10,
						'max_length' => 500,
						'mod_length' => 250,
						'prevent_unreg_using_reg_name' => 1,
						'use_network' => 1,
					);

	$options = get_option($option_name, $defaults);

	$options = wp_parse_args($options, $defaults);

	return $options;

}

The above example works when the default options is single level. If the options are multilevel, these need to be handled differently; I will cover this in the next post in this series.

Click to show/hide the ClassicPress Plugin Development Series Index

ClassicPress Plugin Development: Load and Save Options

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

When developing a plugin, most of them will have settings which need to be saved ad recalled. There are functions available in ClassicPress which you can use to do this:

    get_option

    update_option

If your plugin contains multiple options, then best practice would be to store these in an array within one option rather than each option stored individually.

The get_option is used to load options from the database:

get_option( string $option, mixed $default = false )

Parameters

$option (string) (Required) Name of option to retrieve. Expected to not be SQL-escaped. $default (mixed) (Optional) Default value to return if the option does not exist. Default value: false

Return

(mixed) Value set for the option.

The below is an example of loading options from my SMTP plugin:

$options = get_option( 'azrcrv-smtp' );

The update_option function is used to save options:

update_option( string $option, mixed $value, string|bool $autoload = null )

Parameters

$option (string) (Required) Option name. Expected to not be SQL-escaped. $value (mixed) (Required) Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped. $autoload (string|bool) (Optional) Whether to load the option when ClassicPress starts up. For existing options, $autoload can only be updated using update_option() if $value is also changed. Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options, the default value is 'yes'. Default value: null

Return

(bool) False if value was not updated and true if value was updated.

The below is an example of saving options from my SMTP plugin:

update_option( 'azrcrv-smtp', $options );

Click to show/hide the ClassicPress Plugin Development Series Index

Excel Snippets: Generate Row Numbers

MicrosoftI might not post many Excel snippets, but I’m collecting them into a small Excel Snippets series to make them easy to find.

A while ago, I posted an article on generating row umbers in a SQL script; I fielded a question from someone recently on doing the same thing Excel where the row number changes based on two columns of data. Basically when either of the columns were different, the row number should reset back to 1.

The following formula uses an IF combined with an OR to check if either column of data is different to the row above and if so sets the row number to 1 otherwise it increments by 1:

=IF(OR(A2<>A3,B2<>B3),1,C2+1)

SQL Snippets: Manage Data Containing an Apostrophe

Microsoft SQL ServerThis post is part of the series on SQL Snippets.

I was doing some work with a client recently and they had an issue with some data in SQL Server which they needed change, but weren’t able to do it through the application.

The issue was that they had some names in a column marked as a key field which contained an apostrophe and it was causing them problems; the data should not have had an apostrophe, but they a user had managed to do it and they wanted to do an update to remove it.

There SQL was a little more limited than mine so they asked for assistance. I created the following SQL as an example for them on how data with apostrophe in can be managed.

The example shows how to insert data containing an apostrophe as well as two ways of changing data; one was doing it globally an the other just changing a specific record.

The key to this is that in Microsoft SQL Server you can use one apostrophe to escape another.

-- CREATE TEMP TABLE
CREATE TABLE #Temp(
	USERNAME VARCHAR(15)
)
GO

-- INSERT DATA INTO TEMP TABLE
INSERT INTO #Temp (USERNAME) VALUES ('AJ''ones')
GO

-- SELECT DATA TO CHECK
SELECT * FROM #Temp
GO

-- RUN ONE OF THE TWO UPDATE STATEMENTS
-- remove single quote FROM one record
UPDATE #Temp SET USERNAME = REPLACE(USERNAME, '''', '') WHERE USERNAME = 'AJ''ones'

-- remove single quote FROM all records
UPDATE #Temp SET USERNAME = REPLACE(USERNAME, '''', '') WHERE USERNAME LIKE '%''%'
GO

-- SELECT DATA TO CHECK
SELECT * FROM #Temp
GO

-- DROP TEMP TABLE
DROP TABLE #Temp
GO

SQL Snippets: Series Index

Microsoft SQL ServerThis post is the series index for the series on SQL Snippets.

This series will build up through time as I post snippets of SQL Script; I’ll also go back and update some of the previously posted SQL snippets to bring them together into one index.

SQL Snippets
Manage Data Containing an Apostrophe
SELECT INTO
Create and Use Database Role to Restrict Access
Select Primary Keys for All Tables in Database
Select All Fields for All Tables In Database

Validate and Insert/Update Vendor Emails in Microsoft Dynamics GP from a Text File

Microsoft Dynamics GPI’ve previously posted a script which could be used to update emails in Microsoft Dynamics GP from a tab delimited text file. I’ve recently been working on a project with a client and created a variation on that script which works only for vendor emails, but validates the data before inserting or updating to ensure that the data is valid.

The original script took it on trust that the data was correct, but this tie we had some concerns about the quality of data being provided so I added validation to ensure the vendor and vendor address both existed before any data was inserted or updated; if there were any errors found, the errors were presented to the user to fix and then rerun the script.

The highlighted section is the path to the text file being uploaded; regardless of where you are running SSMS, this path and file must exist on the SQL Server itself.

/*
Created by Ian Grieve of azurecurve | Ramblings of an IT Professional (http://www.azurecurve.co.uk) This code is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0 Int). */
/* CREATE TEMP ERROR TABLE */ CREATE TABLE #Errors ( Error VARCHAR(1000) ,ROW_ID INT IDENTITY ) GO /* CREATE TEMP TABLE FOR DATA */ CREATE TABLE #SY01200_IMPORT ( VENDORID VARCHAR(100) ,ADRSCODE VARCHAR(100) ,EmailToAddress VARCHAR(1000) ,EmailCcAddress VARCHAR(1000) ,EmailBccAddress VARCHAR(1000) ) GO /* BULK INSERT */ BULK INSERT #SY01200_IMPORT FROM 'c:\temp\email.txt' WITH ( FIELDTERMINATOR = '\t' ,ROWTERMINATOR = '\n' ,FIRSTROW = 2 ) GO /* VALIDATE DATA */ -- validate creditors INSERT INTO #Errors (Error) ( SELECT DISTINCT 'Vendor does not exist: ' + CAST(SYI.VENDORID AS VARCHAR(100)) FROM #SY01200_IMPORT AS SYI LEFT JOIN PM00200 AS ['PM Creditor Master File'] ON ['PM Creditor Master File'].VENDORID = SYI.VENDORID WHERE ['PM Creditor Master File'].VENDORID IS NULL ) GO --validate creditor addresses INSERT INTO #Errors (Error) ( SELECT DISTINCT 'Vendor address does not exist: ' + CAST(SYI.VENDORID AS VARCHAR(100)) + ' / ' + CAST(SYI.ADRSCODE AS VARCHAR(100)) FROM #SY01200_IMPORT AS SYI LEFT JOIN PM00300 AS ['PM Creditor Addresses'] ON ['PM Creditor Addresses'].VENDORID = SYI.VENDORID AND ['PM Creditor Addresses'].ADRSCODE = SYI.ADRSCODE WHERE ['PM Creditor Addresses'].VENDORID IS NULL ) GO /* UPDATE EXISTING DATA IF NO ERRORS */ IF (SELECT COUNT(*) FROM #Errors) = 0 UPDATE SY SET SY.EmailToAddress = ISNULL(SY_I.EmailToAddress, '') ,SY.EmailCcAddress = ISNULL(SY_I.EmailCcAddress, '') ,SY.EmailBccAddress = ISNULL(SY_I.EmailBccAddress, '') FROM SY01200 SY INNER JOIN #SY01200_IMPORT AS SY_I ON SY_I.VENDORID = SY.Master_ID AND SY.Master_Type = 'VEN' AND SY.ADRSCODE = SY_I.ADRSCODE GO /* INSERT NEW DATA IF NO ERRORS */ IF (SELECT COUNT(*) FROM #Errors) = 0 INSERT INTO SY01200 ( Master_Type ,Master_ID ,ADRSCODE ,EmailToAddress ,EmailCcAddress ,EmailBccAddress ,INETINFO ) ( SELECT 'VEN' ,VENDORID ,ADRSCODE ,ISNULL(EmailToAddress, '') ,ISNULL(EmailCcAddress, '') ,ISNULL(EmailBccAddress, '') ,'' FROM #SY01200_IMPORT WHERE (SELECT COUNT(Master_ID) FROM SY01200 WHERE Master_Type = 'VEN' AND Master_ID = #SY01200_IMPORT.VENDORID AND ADRSCODE = #SY01200_IMPORT.ADRSCODE) = 0 ) GO /* OUTPUT ERRORS */ IF (SELECT COUNT(*) FROM #Errors) > 0 SELECT Error FROM #Errors ORDER BY ROW_ID GO /* DROP TEMP TABLES */ DROP TABLE #SY01200_IMPORT GO DROP TABLE #Errors GO

Upcoming Microsoft Dynamics GP Webinars from ISC Software

ISC Software SolutionsEvery month at ISC Software I present a webinar on Microsoft Dynamics GP and related products. We typically have the next three upcoming monthly webinars I’ll be delivering scheduled.

We run these webinars on a monthly basis, with occasional extra webinars added to the schedule so it is worth checking the Webinar Schedule page every so often.

The upcoming webinars are:

Lesser Used Modules in Dynamics GP
In July is Lesser Used Modules in Dynamics GP; Explore some of the lesser used modules of Microsoft Dynamics GP and how they can improve processes.

Tue, July 20th, 2021 4:00 PM – 4:45 PM BST

This webinar will look at the modules included in the Microsoft Dynamics GP Starter and Extended Packs, picking out some of the modules which can save time but which aren’t as commonly used.

Register Here

Microsoft Dynamics GP Workflow
In August is Microsoft Dynamics GP Workflow; Discover how workflow can be used to require documents and master record changes to be approved, and enforce segregation of duties.

Tue, August 17th, 2021 4:00 PM – 4:45 PM BST

This webinar will look at the workflow approval types available in Dynamics GP and how they can be used to require documents or master record changes, or document submission to be approved. It will then delve further into the types of steps and routings available within workflow.

Register Here

Getting More From Dynamics GP
In September is Getting More From Dynamics GP; Learn how to get more out of Microsoft Dynamics GP.

Tue, September 14th, 2021 4:00 PM – 4:45 PM BST

Watch while an experienced consultant shows you some tips and tricks to improve your use of Dynamics GP using standard functions and features available now.

Register Here