# UPS Toolkit for i 2.x Documentation


---

# UPS Toolkit for i 2.x System Requirements

> Lists the supported IBM i OS versions (7.3-7.6) for UPS Toolkit for i 2.x.

## Operating System Level Support 

UPS Toolkit for i 2.x can be used on the following operating system versions:

- IBM i OS 7.6
- IBM i OS 7.5
- IBM i OS 7.4
- IBM i OS 7.3

---

# UPS Toolkit for i Changelog

> Version history for UPS Toolkit for i, including the critical 2.10.0 OAuth authentication migration required before June 2024.

The current version of UPS Toolkit for i is **2.10.1**, and was released **September 18th, 2024**.

Starting June 3, 2024, UPS will no longer allow the authentication mechanism used by UPSTI versions prior to 2.10.0 to connect to the UPS APIs. **If you fail to upgrade UPSTI to 2.10.0, your existing version of UPSTI will stop working on June 3, 2024.**

Additionally, UPS has been working to roll out an entirely new API to replace the API that UPSTI has relied on. UPS previously intended for their new API to be the only supported API starting June 3, 2024. However, due to integration issues experienced by customers, UPS has decided to delay enforcing the usage of their new API for an undetermined period of time.

When released, UPSTI 3.0.0 will utilize the new UPS APIs. The new UPS APIs are significantly different, and as a result upgrading to UPSTI 3.0.0 will require code changes for most customers. **When available, UPSTI 3.0.0 will be a required upgrade for all UPSTI customers.**

## 2.10.1 

- Added support for including more than 50 packages in all UPSTI subprocs that involve package data.
- Corrected handling of SSL certificates to ensure UPS SSL certificates would no longer be required in all circumstances.
- Corrected issue with message formatting for UPS9008.
- Corrected issue with field population in UPSSVRSPK.

## 2.10.0

**Upgrading to this release will require recompilation for any programs that utilize the UPSSCRQ database file.**

### Authentication 

- This release implements the new OAuth authentication mechanism required by UPS starting June 3, 2024. To accomodate this new authentication mechanism, the existing UPSUSER database file has been deprecated, and a new file UPSCFGAUTH has been added.
- UPS requires you to register an application with UPS to receive new credentials for use with UPSTI. See [Register an Application with UPS](https://isupport.katointegrations.com/upsti/2.x/register_ups_application.md) for a guide on how to do this.
- The [WRKUPSAUTH Command](https://isupport.katointegrations.com/upsti/2.x/wrkupsauth.md) has been added to allow for authentication configuration and management.
- The primary database file used for the request for each API includes a field named USERID which previously needed to be populated with the username used to sign into the UPS website. This field now needs to be populated with an application name configured via the newly provided WRKUPSAUTH command. The field USERID is not otherwise different.

### Configuration 

- In preparation for UPSTI 3.0.0 being made available later this year, the UPSCFG, UPSACCT, and UPSURL configuration database files have been deprecated.
- The UPSCFG database file has been replaced by the newly added UPSCFGOPT database file. Configuration values stored in UPSCFG must be migrated (where applicable) to the new UPSCFGOPT database file.
- The UPSACCT database file has been replaced by the newly added UPSCFGACCT database file. Configuration values stored in UPSACCT must be migrated (where applicable) to the new UPSCFGACCT database file.
- The UPSURL database file has been replaced by the newly added UPSCFGURL database file. Customers do not need to migrate values from UPSURL to UPSCFGURL unless otherwise instructed by our support team.
- Configuration of default code values (previously configured in the UPSUSER database file) is now done in the UPSCFGOPT database file, and apply to all users. Default values may be specified for currency codes, weight codes, and dimension codes. These default values will be used whenever a corresponding field is left empty for a request. It is no longer possible to set a default value for a UPS service code or packaging type code.

### UPS_shipConfirm() 

- [New] Added new field LBLSIZE to database file UPSSCRQ to allow for configurable label size when calling UPS_shipConfirm(). Valid values for the LBLSIZE field include the newly added constants `UPS_LABEL_SIZE_4X6` and `UPS_LABEL_SIZE_4X8`. If left empty, UPS_shipConfirm() will default to the previous behavior to request 4x6 labels. **If you do not need to request 4x8 labels, you do not need to make code changes, but you still need to recompile any programs using UPSSCRQ.**

### SSL/TLS 

- UPSTI no longer requires SSL certificates be installed to call UPS APIs.

## 2.9.0

**Upgrading to this release may require code changes and recompilation of some or all programs that use UPSTI subprocedures.**

### UPS_tracking() 

- [New] Added signature image and POD letter handling to UPS_tracking()
- [New] Added new example program: T_TK_SIG - signature image and POD letter retrieval

### UPS_shipConfirm() 

**Programs that call this API will need to be recompiled when upgrading to this release.**

- Resolved issue with UPS_shipConfirm() not correctly loading form record for Invoice requests
- Enhanced UPS_shipConfirm() for additional international Invoice handling
- [New] Added constants to UPS copybook for international invoice form types - `UPS_INTL_INVOICE_FULL` and `UPS_INTL_INVOICE_PARTIAL`
- Corrected length for **VALUE** in UPSSCRQPD from `12P 6` to `19P 6`. **This will require recompilation for any programs using UPS_shipConfirm().**
- [New] Added new example program: T_SC_INTL - international invoice creation (must also call T_SA to generate the full invoice PDF)

### General 

- Updated all example programs to use `ACTGRP(*NEW)` instead of `ACTGRP(*CALLER)`

## 2.8.2

- Enhanced performance for internal licensing code

## 2.8.1

### UPS_tracking() 

- Corrected issue which caused some child table records to be generated with incorrect unique IDs. Child records should now have PID values that match the unique IDs of the parent record in all circumstances

## 2.8.0

### UPS_shipConfirm() 

- [New] Added fields to UPSSCRQ to support UPS SurePost®:
  - **USPSENDRS** - USPS Endorsement
  - **USPSSUBCLS** - USPS Sub Class

### UPS_shipAccept() 

- [New] Added fields to UPSSARSPK to support UPS SurePost®:
  - **NMACURCD** - Non-Machineable Charges Currency Code
  - **NMAVAL** - Non-Machineable Charges Monetary Value
  - **SPDASCURCD** - SurePost® DAS Charges Currency Code
  - **SPDASVAL** - SurePost® DAS Charges Monetary Value

### Example Programs 

- [New] Added T_SUREPOST to demonstrate calling UPS_shipConfirm() and UPS_shipAccept() to create a UPS SurePost® shipment

## 2.7.1

### UPS_sAdrVld() 

- Corrected issue which caused UPSXVRS to be populated incorrectly in some scenarios

## 2.7.0

**Upgrading to this release may require code changes and recompilation of some or all programs that use UPSTI subprocedures.**

### UPS_tracking() 

**Programs that call this API will need to be recompiled when upgrading to this release.**

- Enhanced API to allow TrackingOption to be specified in UPSTKRQ to support Mail Innovations tracking. As part of this enhancement, the package and tracking number fields in the UPSTKRQ and UPSTKRSPK were expanded to support the longer Mail Innovations tracking numbers
- Corrected issues preventing activity address lines from being properly populated in some circumstances

### UPS_printZPL() 

- Enhanced printer output to support longer ZPL lines

### UPS_sAdrVld() 

- Enhanced API with new indicator fields for address validity and ambiguity
- Modified behavior of indicator fields in UPSXVRS so that the false condition is populated if an indicator is not present

### UPS_shipConfirm() 

- Corrected issue preventing proper retrieval and decoding of SED forms in some cases
- Resolved intermittent decimal data areas when using certain international forms
- Corrected issue preventing PartiesToTransaction field being sent as part of the request
- Enhanced API to allow shipper address data to be specified in UPSSCRQ, which will override the address data specified in UPSACCT for that request
- Improved error handling to better capture error data returned by UPS

---

# Installing UPS Toolkit for i

> Step-by-step installation guide covering save file creation, FTP transfer, library restoration, IFS restoration, and initial license and configuration setup.

1. Unzip the downloaded file to `C:\temp` (or the directory of your choice).

2. Create the \*SAVF to upload to on your IBM i:

    `CRTSAVF FILE(QGPL/UPSTI) AUT(*ALL)`

3. FTP the file UPSTI.SAVF from your PC to the IBM i. Open a DOS prompt (Start -> Run -> enter 'cmd' and hit enter). Type the following into the DOS prompt, replacing the IP address with that of your IBM i. When prompted, enter your IBM i username and password.

    1. `ftp 123.456.789.123`
    2. `binary`
    3. `lcd c:\temp`
    4. `quote site namefmt 0`
    5. `cd QGPL`
    6. `put UPSTI.savf UPSTI.savf`
    7. `quit`

4. Restore the library from the \*SAVF:

    `RSTLIB SAVLIB(UPSTI) DEV(*SAVF) SAVF(QGPL/UPSTI) RSTLIB(UPSTI)`

5. Add the library to your library list:

    `ADDLIBLE UPSTI`

6. Restore the IFS \*SAVF:

    `RST DEV('/qsys.lib/upsti.lib/ifs.file') OBJ(('/ktprod/upsti' *INCLUDE '/ktprod/upsti')) CRTPRNDIR(*YES)`

7. Apply your license key:

    `APYLIC LICKEY(<<insert key that was emailed to you>>) PRODUCT(UPSTI)`

8. Set up your UPS account and user configurations:

    [Configuring UPSTI](https://isupport.katointegrations.com/upsti/2.x/configuration.md)

---

# Upgrading UPS Toolkit for i

> Procedures for upgrading UPS Toolkit for i, preserving configuration files while restoring updated library objects.

**Note:**
- `####` should be replaced with the version number of the target/new version level with any periods removed (example: for v2.10.0 you would use 2100)

For clarity, you may wish to copy these instructions to a text editor and then perform a scan and replace for the above values before beginning the upgrade.

1. Download the ZIP file from the link provided to you by our support team.

2. Unzip the downloaded file to `C:\temp` (or the directory of your choice).

3. Issue the IBM i command:

    `CRTSAVF FILE(QGPL/UPSTI####) AUT(*ALL)`

4. FTP the file UPSTI.savf from your PC to the IBM i in BINARY mode into the save file that was just created:

    1. Open a DOS prompt (Start -> Run -> type 'cmd' and hit Enter)
    2. Type the following into the DOS prompt, replacing the IP address with that of your IBM i: `ftp 127.0.0.1`
    3. When prompted, enter your user profile and password
    4. Execute the following commands in the DOS prompt to transfer the file:
        1. `binary`
        2. `lcd C:\temp`

            **Note:** Replace `C:\temp` with the location of the UPSTI.savf on your local computer.

        3. `quote site namefmt 0`
        4. `cd QGPL`
        5. `put UPSTI.savf UPSTI####.savf`
        6. `quit`

5. Perform a full backup of your UPSTI library.

6. Execute the following IBM i commands in sequence to upgrade the UPSTI library. Please be careful to enter the commands EXACTLY as listed, except for adjusting the SAVF and/or RSTLIB parameters:

    1. `RSTOBJ OBJ(*ALL) SAVLIB(UPSTI) MBROPT(*ALL) ALWOBJDIF(*FILELVL *OWNER) OMITOBJ((LICP) (UPSCFGOPT) (UPSCFGAUTH) (UPSCFGACCT) (EXAMPLE) (UPSUNQ)) RSTLIB(UPSTI) DEV(*SAVF) SAVF(QGPL/UPSTI####)`

        **Note:** The above RSTOBJ command may produce messages in the job log that indicate that some files were not restored. If this occurs, make a note of each file which was not restored, and then rename each existing file using the RNMOBJ command. After you have renamed each existing file which failed to restore, please retry the above RSTOBJ command.

    2. `RSTOBJ OBJ(UPSCFGOPT UPSCFGAUTH UPSCFGACCT) SAVLIB(UPSTI) OPTION(*NEW) RSTLIB(UPSTI) DEV(*SAVF) SAVF(QGPL/UPSTI###)`

        **Note:** The above RSTOBJ command may report that no objects were restored. This is not an error condition and you should continue with the next step.

    3. `RNMOBJ OBJ(UPSTI/EXAMPLE) OBJTYPE(*FILE) NEWOBJ(EXAMPLE@@@)`

        **Note:** The above RNMOBJ command may instead optionally be replaced with `DLTF FILE(UPSTI/EXAMPLE)` to delete the EXAMPLE source physical file. You should only do this if you are confident that your company has not stored your own source code inside the included EXAMPLE source physical file.

    4. `RSTOBJ OBJ(EXAMPLE) OBJTYPE(*FILE) SAVLIB(UPSTI) MBROPT(*ALL) ALWOBJDIF(*FILELVL *OWNER) RSTLIB(UPSTI) DEV(*SAVF) SAVF(QGPL/UPSTI###)`

7. Execute the following IBM i command to restore updates to necessary files in the IFS (this is all one command):

    `RST DEV('/QSYS.LIB/UPSTI.LIB/IFS.FILE') OBJ(('/ktprod/upsti' *INCLUDE '/ktprod/upsti')) CRTPRNDIR(*YES) PRNDIROWN(QSYS) ALWOBJDIF(*ALL)`

---

# Uninstalling UPS Toolkit for i

> Covers removing UPS Toolkit for i by deleting the UPSTI library and recursively removing the IFS directory.

UPS Toolkit for i licenses may be transferred to a different IBM i, or a different partition. Part of this process will involve uninstalling the product from the original machine/partition.

1. Delete the UPS Toolkit for i install library:

    `DLTLIB UPSTI`

2. Run QShell command to recursively remove the UPS Toolkit for i IFS directory and everything in it:

    `QSH CMD('rm -Rf /ktprod/upsti')`

---

# Register an Application with UPS

> Walkthrough for creating a UPS Developer portal application to obtain the Client ID and Client Secret OAuth credentials required by UPSTI 2.10.0 and later.

Effective June 3, 2024, UPS requires a new method of authentication to communicate with their API which replaces the previous access key based method. All versions of starting with 2.10.0 support this new method of authentication.

To utilize this new authentication mechanism, you are required to use the UPS website to create an "application" which will then provide you with a pair of credentials known as a "Client ID" and a "Client Secret". These two values are mixed case alphanumeric strings 48-64 characters long. You will need to save the Client ID and Client Secret, and use them with the [WRKUPSAUTH Command](https://isupport.katointegrations.com/upsti/2.x/wrkupsauth.md) to allow UPSTI to authenticate and access the UPS API.

Below are the steps required to create an application and retrieve the required "Client ID" and "Client Secret" credentials.

1. Go to the [UPS Developer portal](https://developer.ups.com) and log in using your UPS.com credentials.

2. After logging in, a circle with the first letter of your username should be visible towards the top right of the page. Click it, and select "Apps" from the dropdown menu that appears.

    ![Click Apps in the dropdown menu](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/apps_dropdown.png)

3. If you have already created one or more applications previously, you should be taken to a page which lists all applications. You should click the "Add Apps" link on the bottom left.

    NOTE: If you have not previously created an application, UPS.com may skip taking you to an empty list and will instead take you directly to the "Add Apps" page.

4. On the Add Apps page, UPS will ask you to select the reason you need API credentials. Select **I want to integrate UPS technology into my business** from the dropdown.

    ![Select "I want to integrate UPS technology into my business"](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/credentials_reason.png)

    NOTE: If you select any other answer for this question, UPS will attempt to configure your application in a way that UPSTI is not compatible with.

    UPS will also ask you to choose a UPS shipper account to associate with the credentials.

    Once you've filled out the form, click Next.

5. UPS will then ask you to provide contact information for a Primary Contact. You will need to provide values for the First Name, Last Name, Country, Street Address, City, State, Zip Code, Email, and Phone number fields.

    NOTE: Despite this form wanting a specific person's contact info, UPS recommends that you use a "group inbox" for the email address for the primary contact as you **cannot change the Primary Contact email address assigned to the application without losing access and being required to create a new application**.

    You can optionally specify a separate API Integration Owner, but this form currently appears to be partially broken with some of the fields not being labelled. You can also choose to add a secondary contact, but this form also appears partially broken. Lastly, a checkbox is present to allow you to subscribe to API Status and Update email alerts. We strongly recommend that you do so.

    Once you're done, click Next.

6. UPS will prompt you for an "App Name". The value you choose doesn't matter as it won't be externally visible to anyone, but we do recommend that you make a note of whatever name you use, and use the same name when you configure UPSTI using the [WRKUPSAUTH Command](https://isupport.katointegrations.com/upsti/2.x/wrkupsauth.md). UPS does not appear to have a name length limit, but their website handles the display of very long names poorly, and the [WRKUPSAUTH Command](https://isupport.katointegrations.com/upsti/2.x/wrkupsauth.md) only allows a name up to 32 characters long, so we recommend you limit your name accordingly.

    NOTE: You can ignore the "Callback URL" field as it is not relevant to the method of authentication that UPSTI uses.

    You should select a Billing Account Number from the UPS shipper accounts configured within your UPS.com account.

    On the right side is a large Add Products section, with a multi-page list of different UPS Product APIs. Each UPS API will have a button on the right side that will either be a brown checkmark, or a yellow plus sign.

    - ![Brown Checkmark](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/brown_checkmark.png) A brown checkmark indicates that the API is enabled for your application.
    - ![Yellow Plus Sign](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/yellow_plus.png) A yellow plus sign indicates that the API may be enabled for your application, but is not currently enabled.

    This list controls which UPS APIs your credentials can access. Any credentials which has a yellow plus sign cannot be accessed with these credentials (though it's possible to edit your application and add them later). Once you click a yellow plus sign, it will change to a brown checkmark, **but even though the icon changes, UPS will not record the change until you click the Save button at the bottom of the page**.

    UPSTI relies on the UPS APIs in the list below, so you should ensure that each API in the list has a brown checkmark. By default, only Authorization (OAuth) will have a brown checkmark.

    - Authorization (OAuth)
    - Address Validation
    - Rating
    - Time in Transit
    - Shipping
    - Tracking
    - Pickup

    You should see these APIs appear in a list on the lower left side of the page with a status of "Pending" as each button changes to a brown checkmark. Once each of these APIs appears in that list, click the Save button.

7. Your UPS application should now be created successfully, and the Client ID and Client Secret can be viewed by clicking the small "eye" icon, and can be copied by clicking the "clipboard" icon. As previously mentioned, you will need the Client ID and Client Secret to complete the configuration of UPSTI using the [WRKUPSAUTH Command](https://isupport.katointegrations.com/upsti/2.x/wrkupsauth.md).

    NOTE: Currently the UPS website allows you to view the Client ID and Client Secret again after you leave this page, but this is very atypical (and insecure), so this behavior will hopefully change in the future. For this reason, we recommend securely documenting and storing these credentials somewhere according to your company's policies rather than relying on being able to view them again via the UPS website in the future.

8. Use the [WRKUPSAUTH Command](https://isupport.katointegrations.com/upsti/2.x/wrkupsauth.md) to configure your application within UPSTI, and provide the Client ID and Client Secret you received in step 7.

---

# Replication Instructions

> High-availability and DR guidance, specifying that the LICP file must be excluded from replication.

When setting up replication for high-availability or disaster recovery systems, please exclude the following objects:

- UPSTI/LICP *FILE

---

# License Transfer

> Explains how to transfer a UPS Toolkit for i license from one IBM i system or partition to another.

UPS Toolkit for i licenses may be transferred to a different IBM i, or a different partition. To do this, you will need to provide us with screenshots of the following information with the UPSTI library in your library list:

- The currently installed version of UPS Toolkit for i:

    `DSPVER`

- Machine info for each LPAR a license is being moved from:

    `DSPMCHINF`

- Machine info for each LPAR a license is being moved to:

    `DSPMCHINF`

If you don't currently have access to the system you're migrating to, please let us know and we can provide a temporary license until you can provide information for us to generate a permanent license key.

Please email this information to <a href="mailto:isupport@katointegrations.com">isupport@katointegrations.com</a>.

---

# UPS_shipConfirm()

> Creates and confirms a UPS shipment via the Ship Confirm API, reading from multiple request tables (UPSSCRQ, UPSSCRQPK, UPSSCRQFM, UPSSCRQPD) and writing confirmation data to UPSSCRS.

This subprocedure calls the UPS Ship Confirm API. It reads request data from UPSSCRQ and package information from UPSSCRQPK. For international shipments, additional request information is read from UPSSCRQFM and UPSSCRQPD. Response data is written to UPSSCRS.

**Note:** If you are upgrading from a version older than 2.9.0 and you have programs that use this API, these programs **must** be recompiled.

## UPS Reference Codes 
These codes can be used in the RF1CD and RF2CD fields in UPSSCRQ and UPSSCRQPK.

| Code |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| Description |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| Label Text |
| :-: | - | :- | - | :- |
| `AJ` |     | `Accounts Receivable Customer Account` |     | `Accounts Rec` |
| `AT` |     | `Appropriation Number` |     | `Approp No.` |
| `BM` |     | `Bill of Lading Number` |     | `Bill Lading` |
| `9V` |     | `Collect on Delivery (COD) Number` |     | `COD` |
| `ON` |     | `Dealer Order Number` |     | `Dealer No.` |
| `DP` |     | `Department Number` |     | `Dept No.` |
| `3Q` |     | `FDA Product Code` |     | `FDA Product` |
| `IK` |     | `Invoice Number` |     | `Invoice No.` |
| `MK` |     | `Manifest Key Number` |     | `Manifest No.` |
| `MJ` |     | `Model Number` |     | `Model No.` |
| `PM` |     | `Part Number` |     | `Part No.` |
| `PC` |     | `Production Code` |     | `Prod No.` |
| `PO` |     | `Purchase Order Number` |     | `Purchase No.` |
| `RQ` |     | `Purchase Request Number` |     | `Purchase Req` |
| `RZ` |     | `Return Authorization Number` |     | `Ret Auth No.` |
| `SA` |     | `Salesperson Number` |     | `Salesperson` |
| `SE` |     | `Serial Number` |     | `Serial No.` |
| `ST` |     | `Store Number` |     | `Store No.` |
| `TN` |     | `Transaction Reference Number` |     | `Trx Ref No.` |

*Last updated: Nov 11, 2020*

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_shipConfirm...
     D                 PR              N

      // The ID of the records in UPSSCRQ and other input tables that will be
      //   used to build the request, and under which the response data will be
      //   saved in UPSSCRS.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_SC - Shipment Creation and Confirmation

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_shipConfirm() subprocedure to create a shipment.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSSCRQ, and one or more child
      *   records to UPSSCRQPK. Additional records may also be needed in
      *   UPSSCRQFM and UPSSCRQPD if international shipping is being performed.
      *   Then, call UPS_shipConfirm() passing in your unique ID as well
      *   as the other parameters shown.
      *
      *   UPS_shipConfirm() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSSCRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSSCRQ   UF A E           K DISK    Qualified
     FUPSSCRQPK UF A E           K DISK    Qualified
      // These two files are unused in this example and by most UPSTI users.
     F*UPSSCRQFMUF A E           K DISK    Qualified
     F*UPSSCRQPDUF A E           K DISK    Qualified
     FUPSSCRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D SCRQ            DS                  Likerec(UPSSCRQ.RUPSSCRQ:*Output)
     D SCRQPK          DS                  Likerec(UPSSCRQPK.RUPSSCRQPK:*Output)
     D SCRS            DS                  Likerec(UPSSCRS.RUPSSCRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear SCRQ;
       SCRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       SCRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       SCRQ.AcctNbr = '523FE3';

       SCRQ.StCoName = 'The White House';
       SCRQ.StAddr1 = '1600 Pennsylvania Avenue NW';
       SCRQ.StCity = 'Washington';
       SCRQ.StState = 'DC';
       SCRQ.StPostCd = '20500';
       SCRQ.StCntry = 'US';

       SCRQ.SfCoName = 'Kato Integrations';
       SCRQ.SfAddr1 = '4706 Chiquita Blvd S';
       SCRQ.SfCity = 'Cape Coral';
       SCRQ.SfState = 'FL';
       SCRQ.SfPostCd = '33914';
       SCRQ.SfCntry = 'US';

       SCRQ.SvcCd = '03';

       SCRQ.LblFmtCd = 'ZPL';
       // If LBLSIZE isn't specified, 4x6 will be used as the default.
       //  Valid options are UPS_LABEL_SIZE_4X6 and UPS_LABEL_SIZE_4X8
       SCRQ.LblSize = UPS_LABEL_SIZE_4X6;
       SCRQ.BillType = 'PBS';
       SCRQ.BAcctNbr = '523FE3';

       // Other fields are available but not used in this example code

       write UPSSCRQ.RUPSSCRQ SCRQ;


       // Write individual package child record to UPSSCRQPK
       clear SCRQPK;
       SCRQPK.PID = UniqueID;
       SCRQPK.UID = 1;
       SCRQPK.PkgCd = '02';
       SCRQPK.DimCd = 'IN';
       SCRQPK.Length = 6.5;
       SCRQPK.Width = 10;
       SCRQPK.Height = 4;
       SCRQPK.WgtCd = 'LBS';
       SCRQPK.PkgWgt = 5;

       write UPSSCRQPK.RUPSSCRQPK SCRQPK;

       // If UPS_shipConfirm() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_shipConfirm( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;

         // Read the results from UPSSCRS. There is only going to be one record
         chain UniqueID UPSSCRS.RUPSSCRS SCRS;
         if not %Found(UPSSCRS);
           WriteToJobLog( 'ERROR: No results found in UPSSCRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         WriteToJobLog( 'Result Record: ' + NewLine );
         WriteToJobLog( 'UID: ' + %Char(SCRS.UID) + NewLine );
         WriteToJobLog( 'SHIPNBR: ' + %Trim(SCRS.SHIPNBR) + NewLine );
         WriteToJobLog( 'WGTCD: ' + %Trim(SCRS.WGTCD) + NewLine );
         WriteToJobLog( 'TOTWGT: ' + %Char(SCRS.TOTWGT) + NewLine );
         WriteToJobLog( 'TRSCURCD: ' + %Trim(SCRS.TRSCURCD) + NewLine );
         WriteToJobLog( 'TRSCHRG: ' + %Char(SCRS.TRSCHRG) + NewLine );
         WriteToJobLog( 'SVCCURCD: ' + %Trim(SCRS.SVCCURCD) + NewLine );
         WriteToJobLog( 'SVCCHRG: ' + %Char(SCRS.SVCCHRG) + NewLine );
         WriteToJobLog( 'TOTCURCD: ' + %Trim(SCRS.TOTCURCD) + NewLine );
         WriteToJobLog( 'TOTCHRG: ' + %Char(SCRS.TOTCHRG) + NewLine );
         WriteToJobLog( 'NEGCURCD: ' + %Trim(SCRS.NEGCURCD) + NewLine );
         WriteToJobLog( 'NEGCHRG: ' + %Char(SCRS.NEGCHRG) + NewLine );

         // After this you'd generally move onto calling UPS_shipAccept with
         //  the same UniqueID - refer to example T_SA.
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

### T_SC_INTL - International Shipment Creation with Full Invoice

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_shipConfirm() subprocedure to create an international shipment,
      *   passing the data necessary to trigger the creation of an invoice
      *   document when UPS_shipAccept() is called.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSSCRQ, and one or more child
      *   records to UPSSCRQPK. Additional records are also be needed in
      *   UPSSCRQFM and UPSSCRQPD to support the creation of the invoice.
      *   Then, call UPS_shipConfirm() passing in your unique ID as well
      *   as the other parameters shown.
      *
      *   UPS_shipConfirm() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSSCRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSSCRQ   UF A E           K DISK    Qualified
     FUPSSCRQPK UF A E           K DISK    Qualified
     FUPSSCRQFM UF A E           K DISK    Qualified
     FUPSSCRQPD UF A E           K DISK    Qualified
     FUPSSCRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D SCRQ            DS                  Likerec(UPSSCRQ.RUPSSCRQ:*Output)
     D SCRQPK          DS                  Likerec(UPSSCRQPK.RUPSSCRQPK:*Output)
     D SCRS            DS                  Likerec(UPSSCRS.RUPSSCRS:*Input)
      * International form table data structures
     D SCRQFM          DS                  LikeRec(UPSSCRQFM.RUPSSCRQFM:*Output);
     D SCRQPD          DS                  LikeRec(UPSSCRQPD.RUPSSCRQPD:*Output);

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear SCRQ;
       SCRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       SCRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       SCRQ.AcctNbr = '523FE3';

       SCRQ.StCoName = 'Example Company';
       SCRQ.StAtName = 'A. Person';
       SCRQ.StPhone = '9055551234';
       SCRQ.StAddr1 = '270 Simcoe St N';
       SCRQ.StCity = 'Oshawa';
       SCRQ.StState = 'ON';
       SCRQ.StPostCd = 'L1G 4T5';
       SCRQ.StCntry = 'CA';

       SCRQ.SfCoName = 'Kato Integrations';
       SCRQ.SfAddr1 = '4706 Chiquita Blvd S';
       SCRQ.SfCity = 'Cape Coral';
       SCRQ.SfState = 'FL';
       SCRQ.SfPostCd = '33914';
       SCRQ.SfCntry = 'US';

       SCRQ.SvcCd = '11';

       SCRQ.LblFmtCd = 'ZPL';
       // If LBLSIZE isn't specified, 4x6 will be used as the default.
       //  Valid options are UPS_LABEL_SIZE_4X6 and UPS_LABEL_SIZE_4X8
       SCRQ.LblSize = UPS_LABEL_SIZE_4X6;
       SCRQ.BillType = 'PBS';
       SCRQ.BAcctNbr = '523FE3';

       // Additional fields required for international forms
       SCRQ.SHIPDESC = 'Consumer goods';
       SCRQ.INVFORM = 'I'; // Full invoice
       // Total Cost
       SCRQ.LINVALUE = 123.45;
       SCRQ.LINCURCD = 'USD';

       // Other fields are available but not used in this example code

       write UPSSCRQ.RUPSSCRQ SCRQ;

       // International form fields
       clear SCRQFM;
       SCRQFM.UID = UniqueID;
       SCRQFM.SoCoName = 'Example Company';
       SCRQFM.SoAtName = 'A. Person';
       SCRQFM.SoPhone = '9055551234';
       SCRQFM.SoAddr1 = '270 Simcoe St N';
       SCRQFM.SoCity = 'Oshawa';
       SCRQFM.SoState = 'ON';
       SCRQFM.SoPostCd = 'L1G 4T5';
       SCRQFM.SoCntry = 'CA';
       SCRQFM.CurCd = 'USD';
       SCRQFM.InvNbr = 'INV-21345670';
       SCRQFM.InvDt = %Date();
       SCRQFM.PONbr = '21346570';
       SCRQFM.TermsCd = 'FOB';
       SCRQFM.ExRsnCd = 'SALE';

       write UPSSCRQFM.RUPSSCRQFM SCRQFM;

       // International forms/invoice products
       clear SCRQPD;
       SCRQPD.PID = UniqueID;
       SCRQPD.UID = 1;
       SCRQPD.PARTNBR = 'abc123';
       SCRQPD.DESC1 = 'Description 1 for item abc123';
       SCRQPD.QTY = 1;
       SCRQPD.UNITCD = 'EA';
       SCRQPD.ORGCNTRY = 'US';
       SCRQPD.CMDTYCD = '1234567890';
       SCRQPD.VALUE = 123.45;

       write UPSSCRQPD.RUPSSCRQPD SCRQPD;

       clear SCRQPD;
       SCRQPD.PID = UniqueID;
       SCRQPD.UID = 2;
       SCRQPD.PARTNBR = 'def456';
       SCRQPD.DESC1 = 'Description 2 for item def456';
       SCRQPD.QTY = 1;
       SCRQPD.UNITCD = 'EA';
       SCRQPD.ORGCNTRY = 'US';
       SCRQPD.CMDTYCD = '0001010000';
       SCRQPD.VALUE = 10.10;

       write UPSSCRQPD.RUPSSCRQPD SCRQPD;

       // Write individual package child record to UPSSCRQPK
       clear SCRQPK;
       SCRQPK.PID = UniqueID;
       SCRQPK.UID = 1;
       SCRQPK.PkgCd = '02';
       SCRQPK.DimCd = 'IN';
       SCRQPK.Length = 6.5;
       SCRQPK.Width = 10;
       SCRQPK.Height = 4;
       SCRQPK.WgtCd = 'LBS';
       SCRQPK.PkgWgt = 5;

       write UPSSCRQPK.RUPSSCRQPK SCRQPK;

       clear SCRQPK;
       SCRQPK.PID = UniqueID;
       SCRQPK.UID = 2;
       SCRQPK.PkgCd = '02';
       SCRQPK.DimCd = 'IN';
       SCRQPK.Length = 2.5;
       SCRQPK.Width = 6;
       SCRQPK.Height = 3;
       SCRQPK.WgtCd = 'LBS';
       SCRQPK.PkgWgt = 2;

       write UPSSCRQPK.RUPSSCRQPK SCRQPK;

       // If UPS_shipConfirm() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_shipConfirm( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;

         // Read the results from UPSSCRS. There is only going to be one record
         chain UniqueID UPSSCRS.RUPSSCRS SCRS;
         if not %Found(UPSSCRS);
           WriteToJobLog( 'ERROR: No results found in UPSSCRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         WriteToJobLog( 'Result Record: ' + NewLine );
         WriteToJobLog( 'UID: ' + %Char(SCRS.UID) + NewLine );
         WriteToJobLog( 'SHIPNBR: ' + %Trim(SCRS.SHIPNBR) + NewLine );
         WriteToJobLog( 'WGTCD: ' + %Trim(SCRS.WGTCD) + NewLine );
         WriteToJobLog( 'TOTWGT: ' + %Char(SCRS.TOTWGT) + NewLine );
         WriteToJobLog( 'TRSCURCD: ' + %Trim(SCRS.TRSCURCD) + NewLine );
         WriteToJobLog( 'TRSCHRG: ' + %Char(SCRS.TRSCHRG) + NewLine );
         WriteToJobLog( 'SVCCURCD: ' + %Trim(SCRS.SVCCURCD) + NewLine );
         WriteToJobLog( 'SVCCHRG: ' + %Char(SCRS.SVCCHRG) + NewLine );
         WriteToJobLog( 'TOTCURCD: ' + %Trim(SCRS.TOTCURCD) + NewLine );
         WriteToJobLog( 'TOTCHRG: ' + %Char(SCRS.TOTCHRG) + NewLine );
         WriteToJobLog( 'NEGCURCD: ' + %Trim(SCRS.NEGCURCD) + NewLine );
         WriteToJobLog( 'NEGCHRG: ' + %Char(SCRS.NEGCHRG) + NewLine );

         // After this you'd generally move onto calling UPS_shipAccept with
         //  the same UniqueID - refer to example T_SA.
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSSCRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRQ` | **Record** Shipment Confirmation Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            SHIPDESC      35A` | Shipment Description |
| `A            STCONAME      35A` | Ship to Company Name |
| `A            STATNAME      35A` | Ship to Attn. Name |
| `A            STTAXID       15A` | Ship to Tax ID Number |
| `A            STPHONE       15A` | Ship to Phone Number |
| `A            STFAX         15A` | Ship to Fax Number |
| `A            STEMAIL       50A` | Ship to Email Address |
| `A            STADDR1       35A` | Ship to Address Line 1 |
| `A            STADDR2       35A` | Ship to Address Line 2 |
| `A            STADDR3       35A` | Ship to Address Line 3 |
| `A            STCITY        40A` | Ship to City |
| `A            STSTATE        5A` | Ship to State |
| `A            STPOSTCD      16A` | Ship to Postal Code/Zip |
| `A            STCNTRY        2A` | Ship to Country |
| `A            STRESDNT       1A` | Ship to Residential Address Indicator **Valid Values:** `T`, `Y` |
| `A            SFCONAME      35A` | Ship From Company Name |
| `A            SFATNAME      35A` | Ship From Attn. Name |
| `A            SFTAXID       15A` | Ship From Tax ID Number |
| `A            SFPHONE       15A` | Ship From Phone Number |
| `A            SFFAX         15A` | Ship From Fax Number |
| `A            SFEMAIL       50A` | Ship From Email Address |
| `A            SFADDR1       35A` | Ship From Address Line 1 |
| `A            SFADDR2       35A` | Ship From Address Line 2 |
| `A            SFADDR3       35A` | Ship From Address Line 3 |
| `A            SFCITY        40A` | Ship From City |
| `A            SFSTATE        5A` | Ship From State |
| `A            SFPOSTCD      16A` | Ship From Postal Code/Zip |
| `A            SFCNTRY        2A` | Ship From Country |
| `A            VALIDATE       1A` | Validate Address |
| `A            BILLTYPE       3A` | Billing Type **Valid Values:** `PBS (Prepaid Bill Shipper)`, `BTP (Bill Third Party)`, `FTC (Freight Collect)`, `CSB (Consignee Billed)` |
| `A            BACCTNBR      10A` | Billing Account Number |
| `A            BPOSTCD       16A` | Billing Postal Code/Zip |
| `A            BCNTRY         2A` | Billing Country |
| `A            RETURNCD       1A` | Return Service Code |
| `A            DOCONLY        1A` | Documents Only Indicator **Valid Values:** `T`, `Y` |
| `A            GNIFC          1A` | Goods Not Free Circ. Indicator **Valid Values:** `T`, `Y` |
| `A            NEGRATE        1A` | Negotiated Rate Indicator **Valid Values:** `T`, `Y` |
| `A            MVREFNBR      18A` | Movement Reference Number |
| `A            RF1BC          1A` | Reference Number 1 Barcode **Valid Values:** `T`, `Y` |
| `A            RF1CD          2A` | Reference Number 1 Code |
| `A            RF1VALUE      35A` | Reference Number 1 Value |
| `A            RF2BC          1A` | Reference Number 2 Barcode **Valid Values:** `T`, `Y` |
| `A            RF2CD          2A` | Reference Number 2 Code |
| `A            RF2VALUE      35A` | Reference Number 2 Value |
| `A            SVCCD          4A` | UPS Service Code |
| `A            LINCURCD       3A` | Invoice Line Total Currency Code |
| `A            LINVALUE       8P 0` | Invoice Line Total Value |
| `A            SATDLVR        1A` | Request Saturday Delivery Indicator **Valid Values:** `T`, `Y` |
| `A            INVRMV         1A` | Remove Invoice Indicator **Valid Values:** `T`, `Y` |
| `A            CNEUTRAL       1A` | Carbon Neutral Indicator **Valid Values:** `T`, `Y` |
| `A            DELCNFCD       1A` | Delivery Confirmation Code |
| `A            LBLFMTCD       6A` | Ship Label Format Code |
| `A            INVFORM        1A` | Full (I) or Partial (P) Invoice **Valid Values:** `I`, `P` |
| `A            SEDFORM        1A` | SED Form Indicator **Valid Values:** `T`, `Y` |
| `A            COFORM         1A` | CO Form Indicator **Valid Values:** `T`, `Y` |
| `A            NCOFORM        1A` | NCO Form Indicator **Valid Values:** `T`, `Y` |
| `A            OVRSRADDR      1A` | Override Shipper Address **Valid Values:** `T`, `Y` |
| `A            SRCONAME      35A` | Shipper Company Name |
| `A            SRATNAME      35A` | Shipper Attention Name |
| `A            SRPHONE       15A` | Shipper Phone Number |
| `A            SRADDR1       35A` | Shipper Address Line 1 |
| `A            SRADDR2       35A` | Shipper Address Line 2 |
| `A            SRADDR3       35A` | Shipper Address Line 3 |
| `A            SRCITY        40A` | Shipper City |
| `A            SRSTATE        5A` | Shipper State |
| `A            SRPOSTCD      16A` | Shipper Postal Code |
| `A            SRCNTRY        2A` | Shipper Country |
| `A            SREMAIL       50A` | Shipper Email |
| `A            SRFAX         15A` | Shipper Fax Number |
| `A            SRTAXID       15A` | Shipper Tax ID |
| `A            USPSENDRS      1A` | USPS Endorsement |
| `A            USPSSUBCLS     2A` | USPS Sub Class **Valid Values:** `IR (Irregular)`, `MA (Machineable)` |
| `A            LBLSIZE        3A` | Label Stock Size **Valid Values:** `UPS_LABEL_SIZE_4X6`, `UPS_LABEL_SIZE_4X8` |


### UPSSCRQFM.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRQFM` | **Record** Shipment Confirm Forms Request |
| `A            UID           15P 0` | **Key** Record Unique Id |
| `A            SOOPTION       2A` | Sold To Option |
| `A            SOCONAME      35A` | Sold To Company Name |
| `A            SOATNAME      35A` | Sold to Affn. Name |
| `A            SOTAXID       15A` | Sold to Tax ID Number |
| `A            SOPHONE       15A` | Sold To Phone Number |
| `A            SOADDR1       35A` | Sold to Address Line 1 |
| `A            SOADDR2       35A` | Sold to Address Line 2 |
| `A            SOADDR3       35A` | Sold to Address Line 3 |
| `A            SOCITY        40A` | Sold to City |
| `A            SOSTATE        5A` | Sold to State |
| `A            SOPOSTCD      16A` | Sold to Postal Code/Zip |
| `A            SOCNTRY        2A` | Sold to Country |
| `A            FWCONAME      35A` | Forward Company Name |
| `A            FWTAXID       15A` | Forward Tax ID Number |
| `A            FWADDR1       35A` | Forward Address Line 1 |
| `A            FWADDR2       35A` | Forward Address Line 2 |
| `A            FWADDR3       35A` | Forward Address Line 3 |
| `A            FWCITY        40A` | Forward City |
| `A            FWSTATE        5A` | Forward State |
| `A            FWPOSTCD      16A` | Forward Postal Code/Zip |
| `A            FWCNTRY        2A` | Foward Country |
| `A            UCCONAME      35A` | Ultimate Consignee Company Name |
| `A            UCADDR1       35A` | Ultimate Consignee Address Line 1 |
| `A            UCADDR2       35A` | Ultimate Consignee Address Line 2 |
| `A            UCADDR3       35A` | Ultimate Consignee Address Line 3 |
| `A            UCCITY        40A` | Ultimate Consignee City |
| `A            UCSTATE        5A` | Ultimate Consignee State |
| `A            UCPOSTCD      16A` | Ultimate Consignee Postal Code/Zip |
| `A            UCCNTRY        2A` | Ultimate Consignee Country |
| `A            ICCONAME      35A` | Intermediate Consignee Company Name |
| `A            ICADDR1       35A` | Intermediate Consignee Address Line 1 |
| `A            ICADDR2       35A` | Intermediate Consignee Address Line 2 |
| `A            ICADDR3       35A` | Intermediate Consignee Address Line 3 |
| `A            ICCITY        40A` | Intermediate Consignee City |
| `A            ICSTATE        5A` | Intermediate Consignee State |
| `A            ICPOSTCD      16A` | Intermediate Consignee Postal Code/Zip |
| `A            ICCNTRY        2A` | Intermediate Consignee Country |
| `A            PDOPTION       2A` | Producer Option |
| `A            PDCONAME      35A` | Producer Company Name |
| `A            PDTAXID       15A` | Producer Tax ID Number |
| `A            PDADDR1       35A` | Producer Address Line 1 |
| `A            PDADDR2       35A` | Producer Address Line 2 |
| `A            PDADDR3       35A` | Producer Address Line 3 |
| `A            PDCITY        40A` | Producer City |
| `A            PDSTATE        5A` | Producer State |
| `A            PDPOSTCD      16A` | Producer Postal Code/Zip |
| `A            PDCNTRY        2A` | Producer Country |
| `A            INVNBR        35A` | Invoice Number |
| `A            INVDT           L` | Invoice Date |
| `A            PONBR         35A` | Purchase Order Number |
| `A            TERMSCD        3A` | Terms of Shipment Code |
| `A            EXRSNCD       20A` | Reason for Export Code |
| `A            COMMENTS     150A` | Shipment Comments |
| `A            DECSTMNT     250A` | Declaration Statement |
| `A            DISCOUNT      15P 2` | Discount Amount |
| `A            FRGTCHRG      15P 2` | Freight Charges |
| `A            INSCHRG       15P 2` | Insurance Charges |
| `A            OTHRCHRG      15P 2` | Other Charges |
| `A            OTHRDESC      10A` | Other Charges Description |
| `A            CURCD          3A` | Currency Code |
| `A            BLNKBEG         L` | Blanket Period Begin Date |
| `A            BLNKEND         L` | Blanket Period End Date |
| `A            EXPORTDT        L` | Export Date |
| `A            EXPCARR       35A` | Exporting Carrier |
| `A            CARRIER       17A` | Carrier ID |
| `A            INBONDCD       2A` | In Bond Code |
| `A            ENTRYNBR      25A` | Import Entry Number |
| `A            PNTORGN        5A` | Point of Origin |
| `A            MODTRSCD      35A` | Mode of Transport Code |
| `A            PRTEXP        35A` | Port of Export |
| `A            PRTUNLOAD     35A` | Port of Unloading |
| `A            LOADPIER      35A` | Loading Pier |
| `A            PTYTOTRS       1A` | Parties to Transaction |
| `A            RTEXPTRS       1A` | Routed Export Indicator **Valid Values:** `T`, `Y` |
| `A            CNTNRIZD       1A` | Containerized Indicator **Valid Values:** `T`, `Y` |
| `A            LICNBR        35A` | License Number |
| `A            LICDT           L` | License Date |
| `A            LICEXCCD       4A` | License Exception Code |
| `A            ECCNNBR        8A` | ECCN Number |


### UPSSCRQPD.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRQPD` | **Record** Shipment Confirm Products Request Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            DESC1         35A` | Product Description 1 |
| `A            DESC2         35A` | Product Description 2 |
| `A            DESC3         35A` | Product Description 3 |
| `A            QTY            7P 0` | Product Quantity |
| `A            VALUE         19P 6` | Product Value |
| `A            UNITCD         3A` | Unit Code |
| `A            CMDTYCD       15A` | Commodity Code |
| `A            PARTNBR       10A` | Part Number |
| `A            ORGCNTRY       2A` | Origin Country Code |
| `A            JNTPROD        1A` | Joint Production Indicator **Valid Values:** `T`, `Y` |
| `A            NETCSTCD       1A` | Net Cost Code |
| `A            NETBEGDT        L` | Net Cost Being Date |
| `A            NETENDDT        L` | Net Cost End Date |
| `A            PREFCRIT       1A` | Preference Criteria Code |
| `A            PRODINFO       5A` | Producer Info Code |
| `A            MRKSNBRS      35A` | Marks and Numbers |
| `A            NBRCMDTY       3P 0` | Packages Per Commodity |
| `A            WGTCD          3A` | Weight Code |
| `A            WGT            4P 1` | Product Weight |
| `A            VEHICLID      35A` | Vehicle ID |
| `A            SCDBNBR       10A` | Schedule B Number |
| `A            SCDBQTY       10P 0` | Schedule B Unit Quantity |
| `A            SCDBCD         3A` | Schedule B Unit Code |
| `A            SCDBDESC      20A` | Schedule B Unit Description |
| `A            EXPTYPE        1A` | Export Type |
| `A            SEDVALUE      15P 2` | SED Total Value |


### UPSSCRQPK.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRQPK` | **Record** Shipment Confirm Request Package Information Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            PKGRTN        35A` | Package Return Description |
| `A            PKGCD          2A` | Package Type Code |
| `A            DIMCD          2A` | Package Dimensions Code |
| `A            LENGTH         6P 2` | Package Length |
| `A            WIDTH          6P 2` | Package Width |
| `A            HEIGHT         6P 2` | Package Height |
| `A            WGTCD          3A` | Package Weight Code |
| `A            PKGWGT         8P 2` | Package Weight |
| `A            LRGPKG         1A` | Large Package Indicator **Valid Values:** `T`, `Y` |
| `A            RF1BC          1A` | Reference Number 1 Barcode **Valid Values:** `T`, `Y` |
| `A            RF1CD          2A` | Reference Number 1 Code |
| `A            RF1VALUE      35A` | Reference Number 1 Value |
| `A            RF2BC          1A` | Reference Number 2 Barcode **Valid Values:** `T`, `Y` |
| `A            RF2CD          2A` | Reference Number 2 Code |
| `A            RF2VALUE      35A` | Reference Number 2 Value |
| `A            ADDLHNDL       1A` | Additional Handling Req. **Valid Values:** `T`, `Y` |
| `A            DELCNFCD       1A` | Delivery Confirmation Type Code |
| `A            DELNBR        11A` | Delivery Confirmation Control Number |
| `A            INSVALCD       3A` | Insured Value Code |
| `A            INSCURCD       3A` | Insured Value Currency Code |
| `A            INSVALUE      15P 2` | Insured Value |
| `A            CODFNDCD       1A` | COD Funds Code |
| `A            CODCURCD       3A` | COD Currency Code |
| `A            CODVALUE       8P 2` | COD Value |
| `A            VRBCNFNM      35A` | Verbal Confirmation Name |
| `A            VRBPHONE      15A` | Verbal Confirmation Phone Number |
| `A            SHIPRLS        1A` | Shipper Release Indicator **Valid Values:** `T`, `Y` |


## Output Table Files

### UPSSCRS.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRS` | **Record** Shipment Confirmation Response Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            TRSCURCD       3A` | Transportation Currency Code |
| `A            TRSCHRG       15P 2` | Transportation Charge |
| `A            SVCCURCD       3A` | Service Currency Code |
| `A            SVCCHRG       15P 2` | Service Charge |
| `A            TOTCURCD       3A` | Total Currency Code |
| `A            TOTCHRG       15P 2` | Total Charge |
| `A            WGTCD          3A` | Shipment Weight Code |
| `A            TOTWGT         8P 2` | Shipment Weight |
| `A            SHIPNBR       21A` | Shipment ID Number |
| `A            NEGCURCD       3A` | Negotiated Currency Code |
| `A            NEGCHRG       15P 2` | Negotiated Total Charges |
| `A            DIGEST       256A` | IFS Path to Digest |



---

# UPS_shipAccept()

> Accepts a previously confirmed UPS shipment via the Ship Acceptance API, returning label data and package details in UPSSARS and UPSSARSPK.

This subprocedure calls the UPS Ship Acceptance API. It reads request data from UPSSCRQ and UPSSCRS, and writes response data to UPSSARS, and package data to UPSSARSPK. This subprocedure relies on UPS_shipConfirm() having been called previously, and uses both the request and response data from that transaction.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_shipAccept  PR              N

      // The ID of the record in UPSSCRS that will be used to build the request,
      //   and under which the response data will be saved in UPSSARS and
      //   UPSSARSPK.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_SA - Shipment Acceptance

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_shipAccept() subprocedure to finalize a shipment.
      *
      *   To achieve this, pass the same UniqueID that was passed to a prior
      *   UPS_shipConfirm() call to UPS_shipAccept(). UPS_shipAccept() does
      *   not have request data tables, only response data tables.
      *
      *   UPS_shipAccept() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can read the result data from UPSSARS and UPSSARSPK.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSSARS   IF A E           K DISK    Qualified
     FUPSSARSPK IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D SARS            DS                  Likerec(UPSSARS.RUPSSARS:*Input)
     D SARSPK          DS                  Likerec(UPSSARSPK.RUPSSARSPK:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Replace this with a UniqueID previously used to call
       //  UPS_shipConfirm()
       UniqueID = 1;

       // If UPS_shipAccept() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_shipAccept( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;

         // Read the results from UPSSARS. There is only going to be one record
         chain UniqueID UPSSARS.RUPSSARS SARS;
         if not %Found(UPSSARS);
           WriteToJobLog( 'ERROR: No results found in UPSSARS' + NewLine );
           exsr cleanup;
           return;
         endif;

         WriteToJobLog( 'Result Record: ' + NewLine );
         WriteToJobLog( 'UID: ' + %Char(SARS.UID) + NewLine );
         WriteToJobLog( 'SHIPNBR: ' + %Trim(SARS.SHIPNBR) + NewLine );
         WriteToJobLog( 'WGTCD: ' + %Trim(SARS.WGTCD) + NewLine );
         WriteToJobLog( 'TOTWGT: ' + %Char(SARS.TOTWGT) + NewLine );
         WriteToJobLog( 'TRSCURCD: ' + %Trim(SARS.TRSCURCD) + NewLine );
         WriteToJobLog( 'TRSCHRG: ' + %Char(SARS.TRSCHRG) + NewLine );
         WriteToJobLog( 'SVCCURCD: ' + %Trim(SARS.SVCCURCD) + NewLine );
         WriteToJobLog( 'SVCCHRG: ' + %Char(SARS.SVCCHRG) + NewLine );
         WriteToJobLog( 'TOTCURCD: ' + %Trim(SARS.TOTCURCD) + NewLine );
         WriteToJobLog( 'TOTCHRG: ' + %Char(SARS.TOTCHRG) + NewLine );
         WriteToJobLog( 'NEGCURCD: ' + %Trim(SARS.NEGCURCD) + NewLine );
         WriteToJobLog( 'NEGCHRG: ' + %Char(SARS.NEGCHRG) + NewLine );


         // Next you could read through UPSSARSPK to get package-level info
         //  such as the tracking number, individual service charges, etc.
         //  Most importantly, this is where you'd find the IFS path of
         //  the label you have requested from UPS. If you have requested
         //  a ZPL label, you can then call UPS_printZPL() to print the
         //  label to a spooled file which can then be sent to a
         //  ZPL-compatible printer.
         chain UniqueID UPSSARSPK.RUPSSARSPK SARSPK;
         if not %Found(UPSSARSPK);
           WriteToJobLog( 'ERROR: No results found in UPSSARSPK' + NewLine );
           exsr cleanup;
           return;
         endif;

         dow not %Eof(UPSSARSPK);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'UID: ' + %Char(SARSPK.UID) + NewLine );
           WriteToJobLog( 'TRACKNBR: ' + %Trim(SARSPK.TRACKNBR) + NewLine );
           WriteToJobLog( 'LBLFMT: ' + %Trim(SARSPK.LBLFMT) + NewLine );
           WriteToJobLog( 'LBLPATH: ' + %Trim(SARSPK.LBLIMG) + NewLine );
           WriteToJobLog( 'SVCCURCD: ' + %Trim(SARSPK.SVCCURCD) + NewLine );
           WriteToJobLog( 'SVCCHRG: ' + %Char(SARSPK.SVCCHRG) + NewLine );
           WriteToJobLog( '==========' + NewLine );
           reade UniqueID UPSSARSPK.RUPSSARSPK SARSPK;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSSCRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRQ` | **Record** Shipment Confirmation Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            SHIPDESC      35A` | Shipment Description |
| `A            STCONAME      35A` | Ship to Company Name |
| `A            STATNAME      35A` | Ship to Attn. Name |
| `A            STTAXID       15A` | Ship to Tax ID Number |
| `A            STPHONE       15A` | Ship to Phone Number |
| `A            STFAX         15A` | Ship to Fax Number |
| `A            STEMAIL       50A` | Ship to Email Address |
| `A            STADDR1       35A` | Ship to Address Line 1 |
| `A            STADDR2       35A` | Ship to Address Line 2 |
| `A            STADDR3       35A` | Ship to Address Line 3 |
| `A            STCITY        40A` | Ship to City |
| `A            STSTATE        5A` | Ship to State |
| `A            STPOSTCD      16A` | Ship to Postal Code/Zip |
| `A            STCNTRY        2A` | Ship to Country |
| `A            STRESDNT       1A` | Ship to Residential Address Indicator **Valid Values:** `T`, `Y` |
| `A            SFCONAME      35A` | Ship From Company Name |
| `A            SFATNAME      35A` | Ship From Attn. Name |
| `A            SFTAXID       15A` | Ship From Tax ID Number |
| `A            SFPHONE       15A` | Ship From Phone Number |
| `A            SFFAX         15A` | Ship From Fax Number |
| `A            SFEMAIL       50A` | Ship From Email Address |
| `A            SFADDR1       35A` | Ship From Address Line 1 |
| `A            SFADDR2       35A` | Ship From Address Line 2 |
| `A            SFADDR3       35A` | Ship From Address Line 3 |
| `A            SFCITY        40A` | Ship From City |
| `A            SFSTATE        5A` | Ship From State |
| `A            SFPOSTCD      16A` | Ship From Postal Code/Zip |
| `A            SFCNTRY        2A` | Ship From Country |
| `A            VALIDATE       1A` | Validate Address |
| `A            BILLTYPE       3A` | Billing Type |
| `A            BACCTNBR      10A` | Billing Account Number |
| `A            BPOSTCD       16A` | Billing Postal Code/Zip |
| `A            BCNTRY         2A` | Billing Country |
| `A            RETURNCD       1A` | Return Service Code |
| `A            DOCONLY        1A` | Documents Only Indicator **Valid Values:** `T`, `Y` |
| `A            GNIFC          1A` | Goods Not Free Circ. Indicator **Valid Values:** `T`, `Y` |
| `A            NEGRATE        1A` | Negotiated Rate Indicator **Valid Values:** `T`, `Y` |
| `A            MVREFNBR      18A` | Movement Reference Number |
| `A            RF1BC          1A` | Reference Number 1 Barcode **Valid Values:** `T`, `Y` |
| `A            RF1CD          2A` | Reference Number 1 Code |
| `A            RF1VALUE      35A` | Reference Number 1 Value |
| `A            RF2BC          1A` | Reference Number 2 Barcode **Valid Values:** `T`, `Y` |
| `A            RF2CD          2A` | Reference Number 2 Code |
| `A            RF2VALUE      35A` | Reference Number 2 Value |
| `A            SVCCD          4A` | UPS Service Code |
| `A            LINCURCD       3A` | Invoice Line Total Currency Code |
| `A            LINVALUE       8P 0` | Invoice Line Total Value |
| `A            SATDLVR        1A` | Request Saturday Delivery Indicator **Valid Values:** `T`, `Y` |
| `A            INVRMV         1A` | Remove Invoice Indicator **Valid Values:** `T`, `Y` |
| `A            CNEUTRAL       1A` | Carbon Neutral Indicator **Valid Values:** `T`, `Y` |
| `A            DELCNFCD       1A` | Delivery Confirmation Code |
| `A            LBLFMTCD       6A` | Ship Label Format Code |
| `A            INVFORM        1A` | Full (I) or Partial (P) Invoice **Valid Values:** `I`, `P` |
| `A            SEDFORM        1A` | SED Form Indicator **Valid Values:** `T`, `Y` |
| `A            COFORM         1A` | CO Form Indicator **Valid Values:** `T`, `Y` |
| `A            NCOFORM        1A` | NCO Form Indicator **Valid Values:** `T`, `Y` |


### UPSSCRS.pf

| Field | Description |
|---|---|
| `A          R RUPSSCRS` | **Record** Shipment Confirmation Response Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            TRSCURCD       3A` | Transportation Currency Code |
| `A            TRSCHRG       15P 2` | Transportation Charge |
| `A            SVCCURCD       3A` | Service Currency Code |
| `A            SVCCHRG       15P 2` | Service Charge |
| `A            TOTCURCD       3A` | Total Currency Code |
| `A            TOTCHRG       15P 2` | Total Charge |
| `A            WGTCD          3A` | Shipment Weight Code |
| `A            TOTWGT         8P 2` | Shipment Weight |
| `A            SHIPNBR       21A` | Shipment ID NUmber |
| `A            NEGCURCD       3A` | Negotiated Currency Code |
| `A            NEGCHRG       15P 2` | Negotiated Total Charges |
| `A            DIGEST       256A` | IFS Path to Digest |


## Output Table Files

### UPSSARS.pf

| Field | Description |
|---|---|
| `A          R RUPSSARS` | **Record** Shipment Accept Response Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            TRSCURCD       3A` | Transportation Currency Code |
| `A            TRSCHRG       15P 2` | Transportation Charge |
| `A            SVCCURCD       3A` | Service Currency Code |
| `A            SVCCHRG       15P 2` | Service Charge |
| `A            TOTCURCD       3A` | Total Currency Code |
| `A            TOTCHRG       15P 2` | Total Charge |
| `A            NEGCURCD       3A` | Negotiated Currency Code |
| `A            NEGCHRG       15P 2` | Negotiated Total Charges |
| `A            WGTCD          3A` | Shipment Weight Code |
| `A            TOTWGT         8P 2` | Shipment Weight |
| `A            SHIPNBR       21A` | Shipment ID Number |
| `A            HVALIMG      256A` | High Value Image Path |
| `A            HVALFMT        6A` | High Value Image Format |
| `A            FORMIMG      256A` | International Form Image Path |
| `A            FORMFMT        6A` | Internation Form Image Format |
| `A            CODIMG       256A` | COD Form Image Path |
| `A            CODFMT         6A` | COD Form Image Format |


### UPSSARSPK.pf

| Field | Description |
|---|---|
| `A          R RUPSSARSPK` | **Record** Shipment Accept Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            TRACKNBR      21A` | Package Tracking Number |
| `A            SVCCURCD       3A` | Service Options Currency Code |
| `A            SVCCHRG       15P 2` | Service Charge Cost |
| `A            LBLIMG       256A` | Label Image Path |
| `A            LBLFMT         6A` | Label Image Format |
| `A            HTML         256A` | HTML Path |
| `A            NMACURCD       3A` | Non-Machineable Charges Currency Code |
| `A            NMAVAL        16P 2` | Non-Machineable Charges Monetary Value |
| `A            SPDASCURCD     3A` | SurePost&reg; DAS Charges Currency Code |
| `A            SPDASVAL      16P 2` | SurePost&reg; DAS Charges Monetary Value |



---

# UPS_shipVoid()

> Voids a UPS shipment or individual packages via the Void Shipment API, reading from UPSSVRQ/UPSSVRQPK and writing results to UPSSVRS/UPSSVRSPK.

This subprocedure calls the UPS Void Shipment API. It reads request data from UPSSVRQ and package data from UPSSVRQPK. It writes response data to UPSSVRS and package data to UPSSVRSPK.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_shipVoid    PR              N

      // The ID of the record in UPSSVRQ and UPSSVRQPK that will be used to build
      //   the request, and under which the response data will be saved in UPSSVRS
      //   and UPSSVRSPK.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_SV - Void Shipment

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_shipVoid() subprocedure to void a shipment.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSSVRQ, and one or more child
      *   records to UPSSVRQPK if you need to use "expanded void" capability.
      *   Expanded voiding allows package-level voiding. Then, call
      *   UPS_shipVoid() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_shipVoid() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can read the result data from UPSSVRS, and UPSSVRSPK
      *   if an expanded void was performed.
      *
      *   This example program is only going to demonstrate a basic void.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSSVRQ   UF A E           K DISK    Qualified
     FUPSSVRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D SVRQ            DS                  Likerec(UPSSVRQ.RUPSSVRQ:*Output)
     D SVRS            DS                  Likerec(UPSSVRS.RUPSSVRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear SVRQ;
       SVRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       SVRQ.UserID = 'KATO_TEST';

       // This is a sample shipping number provided by UPS to test shipment
       //  void operations.
       SVRQ.ShipNbr = '1ZISDE016691676846';

       // This is only used in an "expanded void" to allow package-level
       //  voiding. This is covered in example program T_SVEXP
       // SVRQ.ExpVoid = '';

       write UPSSVRQ.RUPSSVRQ SVRQ;

       // If UPS_shipVoid() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_shipVoid( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;

         // Read the results from UPSSVRS. There is only going to be one record
         chain UniqueID UPSSVRS.RUPSSVRS SVRS;
         if not %Found(UPSSVRS);
           WriteToJobLog( 'ERROR: No results found in UPSSVRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         WriteToJobLog( 'Result Record: ' + NewLine );
         WriteToJobLog( 'UID: ' + %Char(SVRS.UID) + NewLine );
         WriteToJobLog( 'STSCD: ' + %Trim(SVRS.STSCD) + NewLine );
         WriteToJobLog( 'STSDSC: ' + %Trim(SVRS.STSDSC) + NewLine );
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

### T_SVEXP - Expanded/Partial Void Shipment

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_shipVoid() subprocedure to void a shipment.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSSVRQ, and one or more child
      *   records to UPSSVRQPK if you need to use "expanded void" capability.
      *   Expanded voiding allows package-level voiding. Then, call
      *   UPS_shipVoid() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_shipVoid() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can read the result data from UPSSVRS, and UPSSVRSPK
      *   if an expanded void was performed.
      *
      *   This example program performs an expanded void to void an individual
      *   package from a shipment.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSSVRQ   UF A E           K DISK    Qualified
     FUPSSVRQPK UF A E           K DISK    Qualified
     FUPSSVRS   IF A E           K DISK    Qualified
     FUPSSVRSPK IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D SVRQ            DS                  Likerec(UPSSVRQ.RUPSSVRQ:*Output)
     D SVRQPK          DS                  Likerec(UPSSVRQPK.RUPSSVRQPK:*Output)
     D SVRS            DS                  Likerec(UPSSVRS.RUPSSVRS:*Input)
     D SVRSPK          DS                  Likerec(UPSSVRSPK.RUPSSVRSPK:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear SVRQ;
       SVRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       SVRQ.UserID = 'KATO_TEST';

       // This is a sample shipping number provided by UPS to test shipment
       //  void operations.
       SVRQ.ShipNbr = '1Z2220060294314162';
       SVRQ.ExpVoid = 'T';
       write UPSSVRQ.RUPSSVRQ SVRQ;

       // When doing an expanded void, write one record to UPSSVRQPK for each
       //  package you wish to void from a shipment.
       clear SVRQPK;
       SVRQPK.PID = UniqueID;
       SVRQPK.UID = 1;

       // Package-level tracking number
       SVRQPK.TrackNbr = '1Z2220060291994175';
       write UPSSVRQPK.RUPSSVRQPK SVRQPK;

       // If UPS_shipVoid() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_shipVoid( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;

         // Read the results from UPSSVRS. There is only going to be one record
         chain UniqueID UPSSVRS.RUPSSVRS SVRS;
         if not %Found(UPSSVRS);
           WriteToJobLog( 'ERROR: No results found in UPSSVRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         WriteToJobLog( 'Result Record: ' + NewLine );
         WriteToJobLog( 'UID: ' + %Char(SVRS.UID) + NewLine );
         WriteToJobLog( 'EXPVOID: ' + %Trim(SVRS.EXPVOID) + NewLine );
         WriteToJobLog( 'STSCD: ' + %Trim(SVRS.STSCD) + NewLine );
         WriteToJobLog( 'STSDSC: ' + %Trim(SVRS.STSDSC) + NewLine );

         // Read the results of each package-level void from UPSSVRSPK.
         chain UniqueID UPSSVRSPK.RUPSSVRSPK SVRSPK;
         if not %Found(UPSSVRSPK);
           WriteToJobLog( 'ERROR: No results found in UPSSVRSPK' + NewLine );
           exsr cleanup;
           return;
         endif;

         dow not %Eof(UPSSVRSPK);
           WriteToJobLog( 'Child Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(SVRSPK.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(SVRSPK.UID) + NewLine );
           WriteToJobLog( 'TRACKNBR: ' + %Trim(SVRSPK.TRACKNBR) + NewLine );
           WriteToJobLog( 'STSCD: ' + %Trim(SVRSPK.STSCD) + NewLine );
           WriteToJobLog( 'STSDSC: ' + %Trim(SVRSPK.STSDSC) + NewLine );
           WriteToJobLog( '==========' + NewLine );
           reade UniqueID UPSSVRSPK.RUPSSVRSPK SVRSPK;
         enddo;

       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSSVRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSSVRQ` | **Record** Shipment Void Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            SHIPNBR       21A` | Shipment ID NUmber |
| `A            EXPVOID        1A` | Expanded Void Indicator **Valid Values:** `T`, `Y` |


### UPSSVRQPK.pf

| Field | Description |
|---|---|
| `A          R RUPSSVRQPK` | **Record** Shipment Void Request Package Information Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            TRACKNBR      21A` | Package Tracking Number |


## Output Table Files

### UPSSVRS.pf

| Field | Description |
|---|---|
| `A          R RUPSSVRS` | **Record** Shipment Void Response Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            EXPVOID        1A` | Expanded Void Indicator **Valid Values:** `T`, `Y` |
| `A            STSCD          1A` | Void Status Code |
| `A            STSDSC        15A` | Void Status Description |


### UPSSVRSPK.pf

| Field | Description |
|---|---|
| `A          R RUPSSVRSPK` | **Record** Shipment Void Response Packge Information Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            TRACKNBR      21A` | Package Tracking Number |
| `A            STSCD          1A` | Void Status Code |
| `A            STSDSC        15A` | Void Status Description |



---

# UPS_printZPL()

> Sends a ZPL label file to a Zebra printer for output.

This subprocedure accepts a ZPL filename and sends it to be printed on a Zebra printer.

## Subprocedure Prototype

```rpgle
     D UPS_printZPL    PR            15P 0

      // ZPL filename for the file to be printed on a Zebra printer device.
     D  pFileName                   256A   Value

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)

     D  pFileControl                   N   Value Options(*Nopass)
```


## Example Code

### T_ZPL - Print to a ZPL Printer

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_printZPL() subprocedure to print a ZPL label returned from UPS.
      *
      *   To achieve this, pass a filepath that was returned in a UPSSARSPK
      *   record as part of a UPS_shipAccept() call. This filepath is in field
      *   LBLIMG. UPS_printZPL() does not have request or response data tables.
      *
      *   UPS_printZPL() will return the UniqueID of the record it printed if
      *   it was successful, or 0 if an error occurred. If an error occurred,
      *   you should look at the fields in ErrorDS to retrieve information about
      *   the error.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D LabelPath       S            256A
      /FREE
       reset ErrorDS;

       // Replace this with a FilePath found in field UPSSARSPK.LBLIMG. The
       //  filepath was built by UPS_shipAccept() using the OUTPUTDIR value
       //  in UPSCFGOPT. For example:
       LabelPath = '/ktprod/upsti/output/label1Z0704W70392392713.zpl';

       // If UPS_printZPL() returns 0, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       // UPS_printZPL() has an optional 3rd parameter that can be used to
       //  control the underlying printer file and improve performance. It
       //  accepts a value of UPS_PRINT_OPEN or UPS_PRINT_CLS. If you pass
       //  UPS_PRINT_OPEN, the underlying printer file is left open until
       //  you either subsequently call UPS_printZPL() with UPS_PRINT_CLS,
       //  or until you call UPS_cleanup(). This feature is generally used
       //  in large batch processing where many ZPL labels are being printed.
       if UPS_printZPL( LabelPath : ErrorDS ) = 0;
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```



---

# UPS_sAdrVld()

> Validates a street-level address via the UPS Street-Level Address Validation API, reading from UPSXVRQ and writing results to UPSXVRS.

This subprocedure calls the UPS Street-Level Address Validation API. It reads request data from UPSXVRQ, and writes response data to UPSXVRS.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_sAdrVld     PR              N

      // The ID of the record in UPSXVRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSXVRS.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_XV - Street-Level Address Validation

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the UPS_sAdrVld()
      *   subprocedure to perform a street-level address validation.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSXVRQ. Then, call
      *   UPS_sAdrVld() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_sAdrVld() will return *On if no error was encountered, or *Off
      *   if an error occurred. If an error occurred, you should look at
      *   the fields in ErrorDS to retrieve information about the error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSXVRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSXVRQ   UF A E           K DISK    Qualified
     FUPSXVRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D XVRQ            DS                  Likerec(UPSXVRQ.RUPSXVRQ:*Output)
     D XVRS            DS                  Likerec(UPSXVRS.RUPSXVRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear XVRQ;
       XVRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       XVRQ.UserID = 'KATO_TEST';

       XVRQ.Addr1 = '4706 Chiquita Blvd S';
       XVRQ.City = 'Cape Coral';
       XVRQ.State = 'FL';
       XVRQ.PostCD = '33914';
       XVRQ.Cntry = 'US';
       write UPSXVRQ.RUPSXVRQ XVRQ;

       // If UPS_sAdrVld() returns *Off, an error occurred and UPS_ErrorDS
       //  should be reviewed to determine the cause.
       if not UPS_sAdrVld( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSXVRS.RUPSXVRS;
         if not %Found(UPSXVRS);
           WriteToJobLog( 'ERROR: No results found in UPSXVRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSXVRS. There are typically multiple
         //  records. A selection of the available fields is output by
         //  this example program but more are availble - review the file
         //  to see what else is available.
         reade UniqueID UPSXVRS.RUPSXVRS XVRS;
         dow not %Eof(UPSXVRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(XVRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(XVRS.UID) + NewLine );
           WriteToJobLog( 'NOCANDS: ' + %Trim(XVRS.NOCANDS) + NewLine );
           WriteToJobLog( 'VALIDADDR: ' + %Trim(XVRS.VALIDADDR) + NewLine );
           WriteToJobLog( 'AMBGADDR: ' + %Trim(XVRS.AMBGADDR) + NewLine );
           WriteToJobLog( 'CLSCD: ' + %Trim(XVRS.CLSCD) + NewLine );
           WriteToJobLog( 'CLSDSC: ' + %Trim(XVRS.CLSDSC) + NewLine );
           WriteToJobLog( 'ADDR1: ' + %Trim(XVRS.ADDR1) + NewLine );
           WriteToJobLog( 'ADDR2: ' + %Trim(XVRS.ADDR2) + NewLine );
           WriteToJobLog( 'ADDR3: ' + %Trim(XVRS.ADDR3) + NewLine );
           WriteToJobLog( 'CITY: ' + %Trim(XVRS.CITY) + NewLine );
           WriteToJobLog( 'STATE: ' + %Trim(XVRS.STATE) + NewLine );
           WriteToJobLog( 'POSTCD: ' + %Trim(XVRS.POSTCD) + NewLine );
           WriteToJobLog( 'CNTRY: ' + %Trim(XVRS.CNTRY) + NewLine );
           WriteToJobLog( '==========' + NewLine );
           reade UniqueID UPSXVRS.RUPSXVRS XVRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSXVRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSXVRQ` | **Record** Street-Level Address Validation Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ADDR1         35A` | Address Line 1 |
| `A            ADDR2         35A` | Address Line 2 |
| `A            ADDR3         35A` | Address Line 3 |
| `A            CITY          40A` | City |
| `A            STATE          5A` | State |
| `A            POSTCD        16A` | Postal Code/Zip |
| `A            CNTRY          2A` | Country |


## Output Table Files

### UPSXVRS.pf

| Field | Description |
|---|---|
| `A          R RUPSXVRS` | **Record** Street-Level Address Validation Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            NOCANDS        1A` | No Candidates Indicator **Valid Values:** `T`, `F` |
| `A            CLSCD          1A` | Address Class Code |
| `A            CLSDSC        15A` | Address Class Description |
| `A            ADDR1         35A` | Address Line 1 |
| `A            ADDR2         35A` | Address Line 2 |
| `A            ADDR3         35A` | Address Line 3 |
| `A            CITY          40A` | City |
| `A            STATE          5A` | State |
| `A            POSTCD        16A` | Postal Code/Zip |
| `A            CNTRY          2A` | Country |
| `A            VALIDADDR      1A` | Valid Address Indicator **Valid Values:** `T`, `F` |
| ` A            AMBGADDR       1A` | Ambiguous Address Indicator **Valid Values:** `T`, `F` |



---

# UPS_ratingReq()

> Retrieves UPS shipping rates via the Rating API, reading from UPSRTRQ/UPSRTRQPK and writing rate and package results to UPSRTRS/UPSRTRSPK.

This subprocedure calls the UPS Rating API. It reads request data from UPSRTRQ, and package data from UPSRTRQPK. It writes response data to UPSRTRS, and package data to UPSRTRSPK.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_ratingReq   PR              N

      // The ID of the records in UPSRTRQ and UPSRTRQPK that will be used to
      //   build the request, and under which the response data will be saved in
      //   UPSRTRS and UPSRTRSPK.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_RT - Rating Request

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_ratingReq() subprocedure to determine shipping rates.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSRTRQ, and one or more child
      *   records to UPSRTRQPK. Then, call UPS_ratingReq() passing in
      *   your unique ID as well as the other parameters shown.
      *
      *   UPS_ratingReq() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSRTRS physical
      *   file, and retrieve the result fields, as well as child records
      *   for each package from UPSRTRSPK.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSRTRQ   UF A E           K DISK    Qualified
     FUPSRTRQPK UF A E           K DISK    Qualified
     FUPSRTRS   IF A E           K DISK    Qualified
     FUPSRTRSPK IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D RTRQ            DS                  Likerec(UPSRTRQ.RUPSRTRQ:*Output)
     D RTRQPK          DS                  Likerec(UPSRTRQPK.RUPSRTRQPK:*Output)
     D RTRS            DS                  Likerec(UPSRTRS.RUPSRTRS:*Input)
     D RTRSPK          DS                  Likerec(UPSRTRSPK.RUPSRTRSPK:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear RTRQ;
       RTRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       RTRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       RTRQ.AcctNbr = '523FE3';

       RTRQ.ReqOpt = 'Rate'; // Rate and validate this shipment
       // Validate the shipment and return rates for all UPS products from the
       //  ShipFrom to the ShipTo
       // RTRQ.ReqOpt = 'Shop';

       RTRQ.PKUPCD = '06';
       RTRQ.CSTCLSCD = '03';

       RTRQ.StAddr1 = '1600 Pennsylvania Avenue NW';
       RTRQ.StCity = 'Washington';
       RTRQ.StState = 'DC';
       RTRQ.StPostCd = '20500';
       RTRQ.StCntry = 'US';

       RTRQ.SfAddr1 = '4706 Chiquita Blvd S';
       //RTRQ.SfAddr2 = 'STE 310';
       RTRQ.SfCity = 'Cape Coral';
       RTRQ.SfState = 'FL';
       RTRQ.SfPostCd = '33914';
       RTRQ.SfCntry = 'US';

       RTRQ.SvcCd = '03';

       // Other fields are available but not used in this example code

       write UPSRTRQ.RUPSRTRQ RTRQ;


       // Write individual package child record to UPSRTRQPK
       clear RTRQPK;
       RTRQPK.PID = UniqueID;
       RTRQPK.UID = 1;
       RTRQPK.PkgCd = '02';
       RTRQPK.DimCd = 'IN';
       RTRQPK.Length = 6.5;
       RTRQPK.Width = 10;
       RTRQPK.Height = 4;
       RTRQPK.WgtCd = 'LBS';
       RTRQPK.PkgWgt = 5;

       write UPSRTRQPK.RUPSRTRQPK RTRQPK;

       // If UPS_ratingReq() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_ratingReq( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSRTRS.RUPSRTRS;
         if not %Found(UPSRTRS);
           WriteToJobLog( 'ERROR: No results found in UPSRTRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSRTRS. A selection of the available fields
         //  is output by this example program but more are availble - review
         //  the file to see what else is available.
         reade UniqueID UPSRTRS.RUPSRTRS RTRS;
         dow not %Eof(UPSRTRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(RTRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(RTRS.UID) + NewLine );
           WriteToJobLog( 'SVCCD: ' + %Trim(RTRS.SVCCD) + NewLine );
           WriteToJobLog( 'SVCDSC: ' + %Trim(RTRS.SVCDSC) + NewLine );
           WriteToJobLog( 'WGTCD: ' + %Trim(RTRS.WGTCD) + NewLine );
           WriteToJobLog( 'TOTWGT: ' + %Char(RTRS.TOTWGT) + NewLine );
           WriteToJobLog( 'TRSCURCD: ' + %Trim(RTRS.TRSCURCD) + NewLine );
           WriteToJobLog( 'TRSCHRG: ' + %Char(RTRS.TRSCHRG) + NewLine );
           WriteToJobLog( 'SVCCURCD: ' + %Trim(RTRS.SVCCURCD) + NewLine );
           WriteToJobLog( 'SVCCHRG: ' + %Char(RTRS.SVCCHRG) + NewLine );
           WriteToJobLog( 'TOTCURCD: ' + %Trim(RTRS.TOTCURCD) + NewLine );
           WriteToJobLog( 'TOTCHRG: ' + %Char(RTRS.TOTCHRG) + NewLine );
           WriteToJobLog( 'GTDDAYS: ' + %Trim(RTRS.GTDDAYS) + NewLine );
           WriteToJobLog( 'GTDTIM: ' + %Char(RTRS.GTDTIM) + NewLine );
           WriteToJobLog( 'NEGCURCD: ' + %Trim(RTRS.NEGCURCD) + NewLine );
           WriteToJobLog( 'NEGCHRG: ' + %Char(RTRS.NEGCHRG) + NewLine );

           // Package level charges can be read from UPSRTRSPK if needed

           reade UniqueID UPSRTRS.RUPSRTRS RTRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSRTRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSRTRQ` | **Record** Rating Request |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            REQOPT         4A` | Request Option **Valid Values:** `RATE`, `SHOP` |
| `A            PKUPCD         2A` | Pickup Type Code |
| `A            CSTCLSCD       2A` | Customer Classification |
| `A            STCONAME      35A` | Ship To Company Name |
| `A            STADDR1       35A` | Ship To Address Line 1 |
| `A            STADDR2       35A` | Ship To Address Line 2 |
| `A            STADDR3       35A` | Ship To Address Line 3 |
| `A            STCITY        40A` | Ship To City |
| `A            STSTATE        5A` | Ship To Provice/State |
| `A            STPOSTCD      16A` | Ship To Postal Code/Zip |
| `A            STCNTRY        2A` | Ship To Country |
| `A            STRESDNT       1A` | Ship To Residential Indicator **Valid Values:** `T`, `Y` |
| `A            SFCONAME      35A` | Ship From Company Name |
| `A            SFADDR1       35A` | Ship From Address Line 1 |
| `A            SFADDR2       35A` | Ship From Address Line 2 |
| `A            SFADDR3       35A` | Ship From Address Line 3 |
| `A            SFCITY        40A` | Ship From City |
| `A            SFSTATE        5A` | Ship From State |
| `A            SFPOSTCD      16A` | Ship From Zip/Postal Code |
| `A            SFCNTRY        2A` | Ship From Country |
| `A            SVCCD          4A` | UPS Service Code |
| `A            DOCONLY        1A` | Documents Only Indicator **Valid Values:** `T`, `Y` |
| `A            SATPKUP        1A` | Request Saturday Pickup Indicator **Valid Values:** `T`, `Y` |
| `A            SATDLVR        1A` | Request Saturday Delivery Indicator **Valid Values:** `T`, `Y` |
| `A            PKUPDAY        2A` | Pickup Day Code |
| `A            PKUPMTHD       2A` | Method to Schedule Pickup |
| `A            CNEUTRAL       1A` | Carbon Neutral Indicator **Valid Values:** `T`, `Y` |
| `A            DELCNFCD       1A` | Delivery Confirmation Type Code |
| `A            NEGRATE        1A` | Negotiated Rate Indicator **Valid Values:** `T`, `Y` |
| `A            INVCURCD       3A` | Invoice Currency Code |
| `A            INVVALUE      10P 2` | Invoice Value |


### UPSRTRQPK.pf

| Field | Description |
|---|---|
| `A          R RUPSRTRQPK` | **Record** Rating Request Package Information |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            PKGCD          2A` | Package Type Code |
| `A            DIMCD          2A` | Package Dimensions Code |
| `A            LENGTH         6P 2` | Package Length |
| `A            WIDTH          6P 2` | Package Width |
| `A            HEIGHT         6P 2` | Package Height |
| `A            WGTCD          3A` | Package Weight Code |
| `A            PKGWGT         8P 2` | Package Weight |
| `A            LRGPKG         1A` | Large Package Indicator **Valid Values:** `T`, `Y` |
| `A            INSCURCD       3A` | Insured Value Currency Code |
| `A            INSVALUE      15P 2` | Insured Value |
| `A            CODFNDCD       1A` | COD Funds Code |
| `A            CODCURCD       3A` | COD Currency Code |
| `A            CODVALUE       8P 2` | COD Value |
| `A            DELCNFCD       1A` | Delivery Confirmation Type Code |
| `A            VRBCNFNM      35A` | Verbal Confirmation Name |
| `A            VRBPHONE      15A` | Verbal Confirmation Phone Number |
| `A            ADDLHNDL       1A` | Additional Handling Req |


## Output Table Files

### UPSRTRS.pf

| Field | Description |
|---|---|
| `A          R RUPSRTRS` | **Record** Rating Request Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            SVCCD          4A` | UPS Service Code |
| `A            SVCDSC        40A` | UPS Service Description |
| `A            WGTCD          3A` | Shipment Weight Code |
| `A            TOTWGT         8P 2` | Shipment Weight |
| `A            TRSCURCD       3A` | Transportation Currency Code |
| `A            TRSCHRG       15P 2` | Transportation Charge |
| `A            SVCCURCD       3A` | Service Currency Code |
| `A            SVCCHRG       15P 2` | Service Charge |
| `A            TOTCURCD       3A` | Total Currency Code |
| `A            TOTCHRG       15P 2` | Total Charge |
| `A            GTDDAYS        8A` | Guaranteed Days to Delivery |
| `A            GTDTIM          T` | Guaranteed Delivery Time |
| `A            NEGCURCD       3A` | Negotiated Currency Code |
| `A            NEGCHRG       15P 2` | Negotiated Total Charges |


### UPSRTRSPK.pf

| Field | Description |
|---|---|
| `A          R RUPSRTRSPK` | **Record** Rating Request Response Package Information |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            TRSCURCD       3A` | Transportation Currency Code |
| `A            TRSCHRG       15P 2` | Transportation Charge |
| `A            SVCCURCD       3A` | Service Currency Code |
| `A            SVCCHRG       15P 2` | Service Charge |
| `A            PKGCURCD       3A` | Package Currency Code |
| `A            PKGCHRG       15P 2` | Package Charge |
| `A            WGTCD          3A` | Package Weight Code |
| `A            PKGWGT         8P 2` | Package Weight |
| `A            BILLWGT        8P 2` | Package Billing Weight |



---

# UPS_tracking()

> Tracks a UPS shipment via the Tracking API, reading from UPSTKRQ and returning package, activity, and reference data in UPSTKRS and related tables.

This subprocedure calls the UPS Tracking API. It reads request data from UPSTKRQ, and writes response data to UPSTKRS, package data to UPSTKRSPK, activity data to UPSTKRSAC, and reference number data to UPSTKRSRF.

**Note:** If you are upgrading from a version older than 2.7.0 and you have programs that use this API, these programs **must** be recompiled.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_tracking    PR              N

      // The ID of the record in UPSTKRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSTKRS and the other
      //   output tables.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_TK - Query Tracking Activity

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_tracking() subprocedure to determine shipping time for a
      *   given shipping option.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSTKRQ. Then, call
      *   UPS_tracking() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_tracking() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSTKRS physical
      *   file, and retrieve the result fields, as well as UPSTKRSAC,
      *   UPSTKRSPK, and UPSTKRSRF for child records.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSTKRQ   UF A E           K DISK    Qualified
     FUPSTKRS   IF A E           K DISK    Qualified
     FUPSTKRSAC IF A E           K DISK    Qualified
     FUPSTKRSPK IF A E           K DISK    Qualified
     FUPSTKRSRF IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D TKRQ            DS                  Likerec(UPSTKRQ.RUPSTKRQ:*Output)
     D TKRS            DS                  Likerec(UPSTKRS.RUPSTKRS:*Input)
     D TKRSAC          DS                  Likerec(UPSTKRSAC.RUPSTKRSAC:*Input)
     D TKRSPK          DS                  Likerec(UPSTKRSPK.RUPSTKRSPK:*Input)
     D TKRSRF          DS                  Likerec(UPSTKRSRF.RUPSTKRSRF:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear TKRQ;
       TKRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       TKRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       TKRQ.AcctNbr = '523FE3';

       TKRQ.ReqOpt = '0'; // Retrieves "Last Activity"
       // TKRQ.ReqOpt = '1'; // Retrieves "All Activity"

       TKRQ.PkgNbr = '1Z12345E0291980793';

       // These fields can be used to perform a search against a reference
       //  number instead of a tracking number.
       //TKRQ.ShipNbr = '';
       //TKRQ.RefNbr = '';
       //TKRQ.BeginDt = '';
       //TKRQ.EndDt = '';
       //TKRQ.DPostCd = '';
       //TKRQ.DCntry = 'US';

       write UPSTKRQ.RUPSTKRQ TKRQ;

       // If UPS_tracking() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_tracking( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSTKRS.RUPSTKRS;
         if not %Found(UPSTKRS);
           WriteToJobLog( 'ERROR: No results found in UPSTKRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSTKRS. There are typically multiple
         //  records. A selection of the available fields is output by
         //  this example program but more are availble - review the file
         //  to see what else is available.
         reade UniqueID UPSTKRS.RUPSTKRS TKRS;
         dow not %Eof(UPSTKRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(TKRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(TKRS.UID) + NewLine );
           WriteToJobLog( 'SHIPNBR: ' + %Trim(TKRS.SHIPNBR) + NewLine );
           WriteToJobLog( 'SHACCT: ' + %Trim(TKRS.SHACCT) + NewLine );
           WriteToJobLog( 'SHADDR1: ' + %Trim(TKRS.SHADDR1) + NewLine );
           WriteToJobLog( 'SHADDR2: ' + %Trim(TKRS.SHADDR2) + NewLine );
           WriteToJobLog( 'SHADDR3: ' + %Trim(TKRS.SHADDR3) + NewLine );
           WriteToJobLog( 'SHCITY: ' + %Trim(TKRS.SHCITY) + NewLine );
           WriteToJobLog( 'SHSTATE: ' + %Trim(TKRS.SHSTATE) + NewLine );
           WriteToJobLog( 'SHPOSTCD: ' + %Trim(TKRS.SHPOSTCD) + NewLine );
           WriteToJobLog( 'SHCNTRY: ' + %Trim(TKRS.SHCNTRY) + NewLine );
           WriteToJobLog( 'STADDR1: ' + %Trim(TKRS.STADDR1) + NewLine );
           WriteToJobLog( 'STADDR2: ' + %Trim(TKRS.STADDR2) + NewLine );
           WriteToJobLog( 'STADDR3: ' + %Trim(TKRS.STADDR3) + NewLine );
           WriteToJobLog( 'STCITY: ' + %Trim(TKRS.STCITY) + NewLine );
           WriteToJobLog( 'STSTATE: ' + %Trim(TKRS.STSTATE) + NewLine );
           WriteToJobLog( 'STPOSTCD: ' + %Trim(TKRS.STPOSTCD) + NewLine );
           WriteToJobLog( 'STCNTRY: ' + %Trim(TKRS.STCNTRY) + NewLine );
           WriteToJobLog( 'WGTCD: ' + %Trim(TKRS.WGTCD) + NewLine );
           WriteToJobLog( 'SHIPWGT: ' + %Char(TKRS.SHIPWGT) + NewLine );
           WriteToJobLog( 'SVCCD: ' + %Trim(TKRS.SVCCD) + NewLine );
           WriteToJobLog( 'SVCDSC: ' + %Trim(TKRS.SVCDSC) + NewLine );
           WriteToJobLog( 'REFNBR: ' + %Trim(TKRS.REFNBR) + NewLine );
           WriteToJobLog( 'REFNBRCD: ' + %Trim(TKRS.REFNBRCD) + NewLine );
           WriteToJobLog( 'PKUPDT: ' + %Char(TKRS.PKUPDT) + NewLine );
           WriteToJobLog( 'SCHEDDT: ' + %Char(TKRS.SCHEDDT) + NewLine );
           WriteToJobLog( 'SCHEDTIM: ' + %Char(TKRS.SCHEDTIM) + NewLine );
           WriteToJobLog( '==========' + NewLine );

           // UPSTKRSPK, UPSTKRSAC, and UPSTKRSRF may contain child records
           //  that could be read here.

           reade UniqueID UPSTKRS.RUPSTKRS TKRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

### T_TKMI - Mail Innovations Tracking

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_tracking() subprocedure to determine shipping time for a
      *   Mail Innovations tracking number.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSTKRQ. Then, call
      *   UPS_tracking() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_tracking() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSTKRS physical
      *   file, and retrieve the result fields, as well as UPSTKRSAC,
      *   UPSTKRSPK, and UPSTKRSRF for child records.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSTKRQ   UF A E           K DISK    Qualified
     FUPSTKRS   IF A E           K DISK    Qualified
     FUPSTKRSAC IF A E           K DISK    Qualified
     FUPSTKRSPK IF A E           K DISK    Qualified
     FUPSTKRSRF IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D TKRQ            DS                  Likerec(UPSTKRQ.RUPSTKRQ:*Output)
     D TKRS            DS                  Likerec(UPSTKRS.RUPSTKRS:*Input)
     D TKRSAC          DS                  Likerec(UPSTKRSAC.RUPSTKRSAC:*Input)
     D TKRSPK          DS                  Likerec(UPSTKRSPK.RUPSTKRSPK:*Input)
     D TKRSRF          DS                  Likerec(UPSTKRSRF.RUPSTKRSRF:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear TKRQ;
       TKRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       TKRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       TKRQ.AcctNbr = '523FE3';

       TKRQ.ReqOpt = '0'; // Retrieves "Last Activity"
       // TKRQ.ReqOpt = '1'; // Retrieves "All Activity"

       TKRQ.PkgNbr = '9102084383041101186729';

       // These fields should be set when searching a Mail Innovations
       //  tracking number
       TKRQ.ShipTypCd = '03';
       TKRQ.TrkOpt = '03';

       // These fields can be used to perform a search against a reference
       //  number instead of a tracking number.
       //TKRQ.ShipNbr = '';
       //TKRQ.RefNbr = '';
       //TKRQ.BeginDt = '';
       //TKRQ.EndDt = '';
       //TKRQ.DPostCd = '';
       //TKRQ.DCntry = 'US';

       write UPSTKRQ.RUPSTKRQ TKRQ;

       // If UPS_tracking() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_tracking( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSTKRS.RUPSTKRS;
         if not %Found(UPSTKRS);
           WriteToJobLog( 'ERROR: No results found in UPSTKRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSTKRS. There are typically multiple
         //  records. A selection of the available fields is output by
         //  this example program but more are availble - review the file
         //  to see what else is available.
         reade UniqueID UPSTKRS.RUPSTKRS TKRS;
         dow not %Eof(UPSTKRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(TKRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(TKRS.UID) + NewLine );
           WriteToJobLog( 'SHIPNBR: ' + %Trim(TKRS.SHIPNBR) + NewLine );
           WriteToJobLog( 'SHACCT: ' + %Trim(TKRS.SHACCT) + NewLine );
           WriteToJobLog( 'SHADDR1: ' + %Trim(TKRS.SHADDR1) + NewLine );
           WriteToJobLog( 'SHADDR2: ' + %Trim(TKRS.SHADDR2) + NewLine );
           WriteToJobLog( 'SHADDR3: ' + %Trim(TKRS.SHADDR3) + NewLine );
           WriteToJobLog( 'SHCITY: ' + %Trim(TKRS.SHCITY) + NewLine );
           WriteToJobLog( 'SHSTATE: ' + %Trim(TKRS.SHSTATE) + NewLine );
           WriteToJobLog( 'SHPOSTCD: ' + %Trim(TKRS.SHPOSTCD) + NewLine );
           WriteToJobLog( 'SHCNTRY: ' + %Trim(TKRS.SHCNTRY) + NewLine );
           WriteToJobLog( 'STADDR1: ' + %Trim(TKRS.STADDR1) + NewLine );
           WriteToJobLog( 'STADDR2: ' + %Trim(TKRS.STADDR2) + NewLine );
           WriteToJobLog( 'STADDR3: ' + %Trim(TKRS.STADDR3) + NewLine );
           WriteToJobLog( 'STCITY: ' + %Trim(TKRS.STCITY) + NewLine );
           WriteToJobLog( 'STSTATE: ' + %Trim(TKRS.STSTATE) + NewLine );
           WriteToJobLog( 'STPOSTCD: ' + %Trim(TKRS.STPOSTCD) + NewLine );
           WriteToJobLog( 'STCNTRY: ' + %Trim(TKRS.STCNTRY) + NewLine );
           WriteToJobLog( 'WGTCD: ' + %Trim(TKRS.WGTCD) + NewLine );
           WriteToJobLog( 'SHIPWGT: ' + %Char(TKRS.SHIPWGT) + NewLine );
           WriteToJobLog( 'SVCCD: ' + %Trim(TKRS.SVCCD) + NewLine );
           WriteToJobLog( 'SVCDSC: ' + %Trim(TKRS.SVCDSC) + NewLine );
           WriteToJobLog( 'REFNBR: ' + %Trim(TKRS.REFNBR) + NewLine );
           WriteToJobLog( 'REFNBRCD: ' + %Trim(TKRS.REFNBRCD) + NewLine );
           WriteToJobLog( 'PKUPDT: ' + %Char(TKRS.PKUPDT) + NewLine );
           WriteToJobLog( 'SCHEDDT: ' + %Char(TKRS.SCHEDDT) + NewLine );
           WriteToJobLog( 'SCHEDTIM: ' + %Char(TKRS.SCHEDTIM) + NewLine );
           WriteToJobLog( '==========' + NewLine );

           // UPSTKRSPK, UPSTKRSAC, and UPSTKRSRF may contain child records
           //  that could be read here.

           reade UniqueID UPSTKRS.RUPSTKRS TKRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

### T_TK_SIG - Signature Image/POD Letter Tracking

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_tracking() subprocedure to retrieve tracking and signature
      *   information for a shipment.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSTKRQ. Then, call
      *   UPS_tracking() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_tracking() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSTKRS physical
      *   file, and retrieve the result fields, as well as UPSTKRSAC,
      *   UPSTKRSPK, and UPSTKRSRF for child records.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSTKRQ   UF A E           K DISK    Qualified
     FUPSTKRS   IF A E           K DISK    Qualified
     FUPSTKRSAC IF A E           K DISK    Qualified
     FUPSTKRSPK IF A E           K DISK    Qualified
     FUPSTKRSRF IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D TKRQ            DS                  Likerec(UPSTKRQ.RUPSTKRQ:*Output)
     D TKRS            DS                  Likerec(UPSTKRS.RUPSTKRS:*Input)
     D TKRSAC          DS                  Likerec(UPSTKRSAC.RUPSTKRSAC:*Input)
     D TKRSPK          DS                  Likerec(UPSTKRSPK.RUPSTKRSPK:*Input)
     D TKRSRF          DS                  Likerec(UPSTKRSRF.RUPSTKRSRF:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear TKRQ;
       TKRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       TKRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       TKRQ.AcctNbr = '523FE3';

       //TKRQ.ReqOpt = '0'; // Retrieves "Last Activity"
       TKRQ.ReqOpt = '15'; // Retrieves "POD, Signature Image, COD, Receiver
                           // Address, All Activity"

       TKRQ.PkgNbr = '1Z12345E0194845039';

       // These fields can be used to perform a search against a reference
       //  number instead of a tracking number.
       //TKRQ.ShipNbr = '';
       //TKRQ.RefNbr = '';
       //TKRQ.BeginDt = '';
       //TKRQ.EndDt = '';
       //TKRQ.DPostCd = '';
       //TKRQ.DCntry = 'US';

       write UPSTKRQ.RUPSTKRQ TKRQ;

       // If UPS_tracking() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_tracking( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSTKRS.RUPSTKRS;
         if not %Found(UPSTKRS);
           WriteToJobLog( 'ERROR: No results found in UPSTKRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSTKRS. There are typically multiple
         //  records. A selection of the available fields is output by
         //  this example program but more are availble - review the file
         //  to see what else is available.
         reade UniqueID UPSTKRS.RUPSTKRS TKRS;
         dow not %Eof(UPSTKRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(TKRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(TKRS.UID) + NewLine );
           WriteToJobLog( 'SHIPNBR: ' + %Trim(TKRS.SHIPNBR) + NewLine );
           WriteToJobLog( 'SHACCT: ' + %Trim(TKRS.SHACCT) + NewLine );
           WriteToJobLog( 'SHADDR1: ' + %Trim(TKRS.SHADDR1) + NewLine );
           WriteToJobLog( 'SHADDR2: ' + %Trim(TKRS.SHADDR2) + NewLine );
           WriteToJobLog( 'SHADDR3: ' + %Trim(TKRS.SHADDR3) + NewLine );
           WriteToJobLog( 'SHCITY: ' + %Trim(TKRS.SHCITY) + NewLine );
           WriteToJobLog( 'SHSTATE: ' + %Trim(TKRS.SHSTATE) + NewLine );
           WriteToJobLog( 'SHPOSTCD: ' + %Trim(TKRS.SHPOSTCD) + NewLine );
           WriteToJobLog( 'SHCNTRY: ' + %Trim(TKRS.SHCNTRY) + NewLine );
           WriteToJobLog( 'STADDR1: ' + %Trim(TKRS.STADDR1) + NewLine );
           WriteToJobLog( 'STADDR2: ' + %Trim(TKRS.STADDR2) + NewLine );
           WriteToJobLog( 'STADDR3: ' + %Trim(TKRS.STADDR3) + NewLine );
           WriteToJobLog( 'STCITY: ' + %Trim(TKRS.STCITY) + NewLine );
           WriteToJobLog( 'STSTATE: ' + %Trim(TKRS.STSTATE) + NewLine );
           WriteToJobLog( 'STPOSTCD: ' + %Trim(TKRS.STPOSTCD) + NewLine );
           WriteToJobLog( 'STCNTRY: ' + %Trim(TKRS.STCNTRY) + NewLine );
           WriteToJobLog( 'WGTCD: ' + %Trim(TKRS.WGTCD) + NewLine );
           WriteToJobLog( 'SHIPWGT: ' + %Char(TKRS.SHIPWGT) + NewLine );
           WriteToJobLog( 'SVCCD: ' + %Trim(TKRS.SVCCD) + NewLine );
           WriteToJobLog( 'SVCDSC: ' + %Trim(TKRS.SVCDSC) + NewLine );
           WriteToJobLog( 'REFNBR: ' + %Trim(TKRS.REFNBR) + NewLine );
           WriteToJobLog( 'REFNBRCD: ' + %Trim(TKRS.REFNBRCD) + NewLine );
           WriteToJobLog( 'PKUPDT: ' + %Char(TKRS.PKUPDT) + NewLine );
           WriteToJobLog( 'SCHEDDT: ' + %Char(TKRS.SCHEDDT) + NewLine );
           WriteToJobLog( 'SCHEDTIM: ' + %Char(TKRS.SCHEDTIM) + NewLine );
           setll TKRS.UID UPSTKRSPK.RUPSTKRSPK;
           reade TKRS.UID UPSTKRSPK.RUPSTKRSPK TKRSPK;
           dow not %Eof(UPSTKRSPK);
             WriteToJobLog( 'SIGIMG: ' + %Trim(TKRSPK.SIGIMG) + NewLine );
             WriteToJobLog( 'PODLTR: ' + %Trim(TKRSPK.PODLTR) + NewLine );
             reade TKRS.UID UPSTKRSPK.RUPSTKRSPK TKRSPK;
           enddo;
           WriteToJobLog( '==========' + NewLine );

           reade UniqueID UPSTKRS.RUPSTKRS TKRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSTKRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSTKRQ` | **Record** Tracking Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            REQOPT         4A` | Tracking Request Option |
| `A            PKGNBR        34A` | Package Number |
| `A            SHIPNBR       21A` | Shipment Number |
| `A            REFNBR        35A` | Reference Number |
| `A            BEGINDT         L` | Period Begin Date |
| `A            ENDDT           L` | Period End Date |
| `A            DPOSTCD       16A` | Destination Postal Code |
| `A            DCNTRY         2A` | Destination Country |
| `A            SHIPTYPCD      2A` | Shipment Type Code |
| `A            SHIPTYPDSC    15A` | Shipment Type Description |
| `A            TRKOPT         2A` | Tracking Option |


## Output Table Files

### UPSTKRS.pf

| Field | Description |
|---|---|
| `A          R RUPSTKRS` | **Record** Tracking Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            SHIPNBR       21A` | Shipment ID Number |
| `A            SHACCT        10A` | Shipper Account Number |
| `A            SHADDR1       35A` | Shipper Address Line 1 |
| `A            SHADDR2       35A` | Shipper Address Line 2 |
| `A            SHADDR3       35A` | Shipper Address Line 3 |
| `A            SHCITY        40A` | Shipper City |
| `A            SHSTATE        5A` | Shipper State |
| `A            SHPOSTCD      16A` | Shipper Postal Code/Zip |
| `A            SHCNTRY        2A` | Shipper Country |
| `A            STADDR1       35A` | Ship To Address Line 1 |
| `A            STADDR2       35A` | Ship To Address Line 2 |
| `A            STADDR3       35A` | Ship To Address Line 3 |
| `A            STCITY        40A` | Ship To City |
| `A            STSTATE        5A` | Ship To State |
| `A            STPOSTCD      16A` | Ship To Postal Code/Zip |
| `A            STCNTRY        2A` | Ship To Country |
| `A            WGTCD          3A` | Shipment Weight Code |
| `A            SHIPWGT       10P 2` | Shipment Weight |
| `A            SVCCD          4A` | UPS Service Code |
| `A            SVCDSC        40A` | UPS Service Description |
| `A            REFNBR        35A` | Shipment Reference Number |
| `A            REFNBRCD       2A` | Shipment Reference Code |
| `A            PKUPDT          L` | Shipment Pickup Date |
| `A            SCHEDDT         L` | Scheduled Delivery Date |
| `A            SCHEDTIM        T` | Scheduled Delivery Time |


### UPSTKRSPK.pf

| Field | Description |
|---|---|
| `A          R RUPSTKRSPK` | **Record** Tracking Response Package Information Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            TRACKNBR      34A` | Package Tracking Number |
| `A            RSCHDDT         L` | Rescheduled Delivery Date |
| `A            RSCHDTIM        T` | Rescheduled Delivery Time |
| `A            RRADDR1       35A` | Rerouted Address Line 1 |
| `A            RRADDR2       35A` | Rerouted Address Line 2 |
| `A            RRADDR3       35A` | Rerouted Address Line 3 |
| `A            RRCITY        40A` | Rerouted City |
| `A            RRSTATE        5A` | Rerouted State |
| `A            RRPOSTCD      16A` | Rerouted Postal Code/Zip |
| `A            RRCNTRY        2A` | Rerouted Country |
| `A            RTADDR1       35A` | Return To Sender Address Line 1 |
| `A            RTADDR2       35A` | Return To Sender Address Line 2 |
| `A            RTADDR3       35A` | Return To Sender Address Line 3 |
| `A            RTCITY        40A` | Return To Sender City |
| `A            RTSTATE        5A` | Return To Sender State |
| `A            RTPOSTCD      16A` | Return To Postal Code/Zip |
| `A            RTCNTRY        2A` | Return To Country |
| `A            CODCURCD       3A` | COD Currency Code |
| `A            CODVALUE      11P 2` | COD Value |
| `A            CODCTRL       12A` | COD Control Number |
| `A            CODSTS        13A` | COD Status |
| `A            SIGREQCD       2A` | Signature Required Code |
| `A            MSGCD          2A` | Message Code |
| `A            MSGDESC       15A` | Message Description |
| `A            WGTCD          3A` | Package Weight Code |
| `A            PKGWGT         7P 2` | Package Weight |
| `A            SIGIMG       256A` | Signature Image Path |
| `A            SIGFMT         6A` | Signature Image Format |
| `A            PODLTR       256A` | POD Letter Path |


### UPSTKRSAC.pf

| Field | Description |
|---|---|
| `A          R RUPSTKRSAC` | **Record** Tracking Package Activity Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            ACADDR1       35A` | Activity Address Line 1 |
| `A            ACADDR2       35A` | Activity Address Line 2 |
| `A            ACADDR3       35A` | Activity Address Line 3 |
| `A            ACCITY        40A` | Activity City |
| `A            ACSTATE       5A` | Activity State |
| `A            ACPOSTCD      16A` | Activity Postal Code/Zip |
| `A            ACCNTRY        2A` | Activity Country |
| `A            LOCCD          2A` | Activity Location Code |
| `A            LOCDESC       35A` | Activity Location Description |
| `A            SIGNEDBY      30A` | Signed For By |
| `A            STSTYPCD       1A` | Status Type Code |
| `A            STSTYP       300A` | Status Type |
| `A            STSCD          2A` | Status Code |
| `A            ACTIVDT         L` | Activity Date |
| `A            ACTIVTIM        T` | Activity Time |
| `A            TRANFACTYP     2A` | Transport Facility Type |
| `A            TRANFACCD      5A` | Transport Facility Code |
| `A            SIGIMG       256A` | Signature Image Path |
| `A            SIGFMT         6A` | Signature Image Format |
| `A            PODLTR       256A` | POD Letter Path |


### UPSTKRSRF.pf

| Field | Description |
|---|---|
| `A          R RUPSTKRSRF` | **Record** Tracking Response Package Reference Number Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            REFNBR        35A` | Reference Number |
| `A            REFNBRCD       2A` | Reference Number Code |



---

# UPS_timeInTransit()

> Estimates UPS transit time via the Time in Transit API, reading from UPSTTRQ and writing results to UPSTTRS.

This subprocedure calls the UPS Time in Transit API. It reads request data from UPSTTRQ and writes response data to UPSTTRS.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_timeInTransit...
     D                 PR              N

      // The ID of the record in UPSTTRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSTTRS.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_TT - Query Time and Transit

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_timeInTransit() subprocedure to determine shipping time for a
      *   given shipping option.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSTTRQ. Then, call
      *   UPS_timeInTransit() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_timeInTransit() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSTTRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSTTRQ   UF A E           K DISK    Qualified
     FUPSTTRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D TTRQ            DS                  Likerec(UPSTTRQ.RUPSTTRQ:*Output)
     D TTRS            DS                  Likerec(UPSTTRS.RUPSTTRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear TTRQ;
       TTRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       TTRQ.UserID = 'KATO_TEST';

       TTRQ.StCity = 'Washington';
       TTRQ.StState = 'DC';
       TTRQ.StPostCd = '20500';
       TTRQ.StCntry = 'US';

       TTRQ.SfCity = 'Cape Coral';
       TTRQ.SfState = 'FL';
       TTRQ.SfPostCd = '33914';
       TTRQ.SfCntry = 'US';

       TTRQ.WgtCd = 'LBS';
       TTRQ.Wgt = 3.5;
       TTRQ.TotPkgs = 1;

       TTRQ.PkUpDt = %Date();
       TTRQ.CurCd = 'USD';
       TTRQ.Value = 75.00;

       write UPSTTRQ.RUPSTTRQ TTRQ;

       // If UPS_timeInTransit() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_timeInTransit( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSTTRS.RUPSTTRS;
         if not %Found(UPSTTRS);
           WriteToJobLog( 'ERROR: No results found in UPSTTRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSTTRS. There are typically multiple
         //  records. A selection of the available fields is output by
         //  this example program but more are availble - review the file
         //  to see what else is available.
         reade UniqueID UPSTTRS.RUPSTTRS TTRS;
         dow not %Eof(UPSTTRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(TTRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(TTRS.UID) + NewLine );
           WriteToJobLog( 'SVCCD: ' + %Trim(TTRS.SVCCD) + NewLine );
           WriteToJobLog( 'SVCDSC: ' + %Trim(TTRS.SVCDSC) + NewLine );
           WriteToJobLog( 'GRNTEED: ' + %Trim(TTRS.GRNTEED) + NewLine );
           WriteToJobLog( 'DOCONLY: ' + %Trim(TTRS.DOCONLY) + NewLine );
           WriteToJobLog( 'AUTDTYCD: ' + %Trim(TTRS.AUTDTYCD) + NewLine );
           WriteToJobLog( 'WEEKDAY: ' + %Trim(TTRS.WEEKDAY) + NewLine );
           WriteToJobLog( 'ARRIVTIM: ' + %Char(TTRS.ARRIVTIM) + NewLine );
           WriteToJobLog( 'ARRIVDT: ' + %Char(TTRS.ARRIVDT) + NewLine );
           WriteToJobLog( 'PKUPTIM: ' + %Char(TTRS.PKUPTIM) + NewLine );
           WriteToJobLog( 'PKUPDT: ' + %Char(TTRS.PKUPDT) + NewLine );
           WriteToJobLog( 'TRANSBUS: ' + %Char(TTRS.TRANSBUS) + NewLine );
           WriteToJobLog( 'TRANSTOT: ' + %Char(TTRS.TRANSTOT) + NewLine );
           WriteToJobLog( 'CUTOFF: ' + %Char(TTRS.CUTOFF) + NewLine );
           WriteToJobLog( 'RESTDAYS: ' + %Char(TTRS.RESTDAYS) + NewLine );
           WriteToJobLog( 'HOLIDAYS: ' + %Char(TTRS.HOLIDAYS) + NewLine );
           WriteToJobLog( 'CUSTOMS: ' + %Char(TTRS.CUSTOMS) + NewLine );
           WriteToJobLog( '==========' + NewLine );
           reade UniqueID UPSTTRS.RUPSTTRS TTRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSTTRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSTTRQ` | **Record** Time in Transit Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            STTOWN        30A` | Ship To Town |
| `A            STCITY        40A` | Ship To City |
| `A            STSTATE        5A` | Ship To State |
| `A            STPOSTCD      16A` | Ship To Postal Code/Zip |
| `A            STCNTRY        2A` | Ship To Country |
| `A            STRESDNT       1A` | Ship To Residential Indicator **Valid Values:** `T`, `Y` |
| `A            SFTOWN        30A` | Ship From Town |
| `A            SFCITY        40A` | Ship From City |
| `A            SFSTATE        5A` | Ship From State |
| `A            SFPOSTCD      16A` | Ship From Postal Code/Zip |
| `A            SFCNTRY        2A` | Ship From Country |
| `A            WGTCD          3A` | Weight Code |
| `A            WGT            5P 2` | Weight |
| `A            TOTPKGS       10P 0` | Total Number of Packages |
| `A            PKUPDT          L` | Pickup Date |
| `A            CURCD          3A` | Currency Code |
| `A            VALUE         11P 2` | Value |
| `A            DOCONLY        1A` | Documents Only Indicator **Valid Values:** `T`, `Y` |
| `A            RESULTS        2P 0` | Max Results |


## Output Table Files

### UPSTTRS.pf

| Field | Description |
|---|---|
| `A          R RUPSTTRS` | **Record** Time in Transit Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            SVCCD          4A` | UPS Service Code |
| `A            SVCDSC        50A` | UPS Service Description |
| `A            GRNTEED        1A` | Guaranteed Indicator |
| `A            DOCONLY        1A` | Documents Only Indicator |
| `A            AUTDTYCD       2A` | Auto Duty Code |
| `A            WEEKDAY        3A` | Arrival Day of the Week |
| `A            ARRIVTIM        T` | Arrival Time |
| `A            ARRIVDT         L` | Arrival Date |
| `A            PKUPTIM         T` | Pickup Time |
| `A            PKUPDT          L` | Pickup Date |
| `A            TRANSBUS       2P 0` | Business Transit Days |
| `A            TRANSTOT       2P 0` | Total Transit Days |
| `A            CUTOFF          T` | Customer Center Call Time |
| `A            RESTDAYS       2P 0` | Non-Movement Days |
| `A            HOLIDAYS       2P 0` | Holidays |
| `A            CUSTOMS        2P 0` | Days Delayed By Customs |



---

# UPS_adrVld()

> Validates a city/state/ZIP address via the UPS Address Validation API, reading from UPSAVRQ and writing results to UPSAVRS.

This subprocedure calls the UPS Address Validation API for city/state/zip address validation. It reads in request data from UPSAVRQ and writes response data to UPSAVRS.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_adrVld      PR              N

      // The ID of the record in UPSAVRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSAVRS.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_AV - Address Validation

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the UPS_adrVld()
      *   subprocedure to perform a non-street-level address validation.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSAVRQ. Then, call
      *   UPS_adrVld() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_adrVld() will return *On if no error was encountered, or *Off
      *   if an error occurred. If an error occurred, you should look at
      *   the fields in ErrorDS to retrieve information about the error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSAVRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSAVRQ   UF A E           K DISK    Qualified
     FUPSAVRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D AVRQ            DS                  Likerec(UPSAVRQ.RUPSAVRQ:*Output)
     D AVRS            DS                  Likerec(UPSAVRS.RUPSAVRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear AVRQ;
       AVRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       AVRQ.UserID = 'KATO_TEST';

       AVRQ.State = 'MN';
       AVRQ.PostCD = '56001';
       write UPSAVRQ.RUPSAVRQ AVRQ;

       // If UPS_adrVld() returns *Off, an error occurred and UPS_ErrorDS
       //  should be reviewed to determine the cause.
       if not UPS_adrVld( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSAVRS.RUPSAVRS;
         if not %Found(UPSAVRS);
           WriteToJobLog( 'ERROR: No results found in UPSAVRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSAVRS. There are typically multiple
         //  records. A selection of the available fields is output by
         //  this example program but more are availble - review the file
         //  to see what else is available.
         reade UniqueID UPSAVRS.RUPSAVRS AVRS;
         dow not %Eof(UPSAVRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(AVRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(AVRS.UID) + NewLine );
           WriteToJobLog( 'RANK: ' + %Char(AVRS.RANK) + NewLine );
           WriteToJobLog( 'QUALITY: ' + %Char(AVRS.QUALITY) + NewLine );
           WriteToJobLog( 'CITY: ' + %Trim(AVRS.CITY) + NewLine );
           WriteToJobLog( 'STATE: ' + %Trim(AVRS.STATE) + NewLine );
           WriteToJobLog( 'POSTCDL: ' + %Trim(AVRS.POSTCDL) + NewLine );
           WriteToJobLog( 'POSTCDH: ' + %Trim(AVRS.POSTCDH) + NewLine );
           WriteToJobLog( '==========' + NewLine );
           reade UniqueID UPSAVRS.RUPSAVRS AVRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSAVRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSAVRQ` | **Record** AV Request Record |
| `A           UID           15P 0` | **Key** Record Unique ID |
| `A           USERID        30A` | UPS User ID |
| `A           CITY          40A` | City |
| `A           STATE          5A` | State |
| `A           POSTCD        16A` | Postal Code |


## Output Table Files

### UPSAVRS.pf

| Field | Description |
|---|---|
| `A          R RUPSAVRS` | **Record** Address Validation Response Record |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            RANK          10P 0` | Result Rank |
| `A            QUALITY        3P 2` | Result Quality |
| `A            CITY          40A` | City |
| `A            STATE          5A` | State |
| `A            POSTCDL       16A` | Postal Code Low |
| `A            POSTCDH       16A` | Postal Code High |



---

# UPS_pkupCreate()

> Creates a UPS pickup via the Pickup Creation API, reading from UPSPCRQ/UPSPCRQTK and writing response and charge data to UPSPCRS/UPSPCRSCG.

This subprocedure calls the UPS Pickup Creation API. It reads request data from UPSPCRQ, and tracking number data from UPSPCRQTK. It writes response data to UPSPCRS, and charge data to UPSPCRSCG.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_pkupCreate  PR              N

      // The ID of the records in UPSPCRQ and other input tables that will be
      //   used to build the request, and under which the response data will be
      //   saved in UPSPCRS and UPSPCRSCG.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_PC - Pickup Creation

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_pkupCreate() subprocedure to schedule a pickup.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSPCRQ, and one or more child
      *   records to UPSPCRQTK. Then, call UPS_pkupCreate() passing in
      *   your unique ID as well as the other parameters shown.
      *
      *   UPS_pkupCreate() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSPCRS physical
      *   file, and retrieve the result fields, as well as child records
      *   for each package from UPSPCRSCG.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSPCRQ   UF A E           K DISK    Qualified
     FUPSPCRQTK UF A E           K DISK    Qualified
     FUPSPCRS   IF A E           K DISK    Qualified
     FUPSPCRSCG IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D PCRQ            DS                  Likerec(UPSPCRQ.RUPSPCRQ:*Output)
     D PCRQTK          DS                  Likerec(UPSPCRQTK.RUPSPCRQTK:*Output)
     D PCRS            DS                  Likerec(UPSPCRS.RUPSPCRS:*Input)
     D PCRSCG          DS                  Likerec(UPSPCRSCG.RUPSPCRSCG:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear PCRQ;
       PCRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       PCRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       PCRQ.AcctNbr = '523FE3';

       PCRQ.RTPKUP = 'N';
       PCRQ.CLSTIM = %Time() + %Hours(6);
       PCRQ.RDYTIM = %Time() + %Hours(2);
       PCRQ.PKUPDT = %Date() + %Days(1);
       PCRQ.PCONAME = 'Kato Integrations';
       PCRQ.PCNNAME = 'Bob Smith';
       PCRQ.PADDR1 = '4706 Chiquita Blvd S';
       PCRQ.PROOM = 'PMB 411';
       PCRQ.PCITY = 'Cape Coral';
       PCRQ.PSTATE = 'FL';
       PCRQ.PPOSTCD = '33914';
       PCRQ.PCNTRY = 'US';
       PCRQ.PPHONE = '18005736435';
       PCRQ.ALTADDR = 'Y';
       PCRQ.TOTWGT = 1.0;
       PCRQ.WGTCD = 'LBS';
       PCRQ.LRGPKG = 'N';
       PCRQ.PAYMTHD = '01';
       PCRQ.SVCCD = '002';
       PCRQ.QTY = 1;
       PCRQ.DCNTRY = 'US';
       PCRQ.CNTNRCD = '01';
       // Other fields are available but not used in this example code

       write UPSPCRQ.RUPSPCRQ PCRQ;

       // Records can be written to UPSPCRQTK to provide tracking numbers for
       //  return packages. A maximum of 30 can be provided. This is optional
       //  and not used in this example.
       // clear PCRQTK;
       // PCRQTK.PID = UniqueID;
       // PCRQTK.UID = 1;
       // PCRQTK.RTRACK = '';

       // write UPSPCRQPK.RUPSPCRQPK PCRQTK;

       // If UPS_pkupCreate() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_pkupCreate( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSPCRS.RUPSPCRS;
         if not %Found(UPSPCRS);
           WriteToJobLog( 'ERROR: No results found in UPSPCRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSPCRS. A selection of the available fields
         //  is output by this example program but more are availble - review
         //  the file to see what else is available.
         reade UniqueID UPSPCRS.RUPSPCRS PCRS;
         dow not %Eof(UPSPCRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'UID: ' + %Char(PCRS.UID) + NewLine );
           WriteToJobLog( 'REQNBR: ' + %Trim(PCRS.REQNBR) + NewLine );
           WriteToJobLog( 'RTCD: ' + %Trim(PCRS.RTCD) + NewLine );
           WriteToJobLog( 'RTDSC: ' + %Trim(PCRS.RTDSC) + NewLine );
           WriteToJobLog( 'RTTYPE: ' + %Trim(PCRS.RTTYPE) + NewLine );
           WriteToJobLog( 'CURCD: ' + %Trim(PCRS.CURCD) + NewLine );
           WriteToJobLog( 'TOTTAX: ' + %Char(PCRS.TOTTAX) + NewLine );
           WriteToJobLog( 'TOTCHRG: ' + %Char(PCRS.TOTCHRG) + NewLine );

           // Read through UPSSCRSPG for package-level charges. Depending on
           //  your request, there may not be any.
           chain UniqueID UPSPCRSCG.RUPSPCRSCG PCRSCG;
           if not %Found(UPSPCRSCG);
             WriteToJobLog( 'No results found in UPSPCRSCG' + NewLine );
             exsr cleanup;
             return;
           endif;

           dow not %Eof(UPSPCRSCG);
             WriteToJobLog( 'Child Result Record: ' + NewLine );
             WriteToJobLog( 'PID: ' + %Char(PCRSCG.PID) + NewLine );
             WriteToJobLog( 'UID: ' + %Char(PCRSCG.UID) + NewLine );
             WriteToJobLog( 'CHRGCD: ' + %Trim(PCRSCG.CHRGCD) + NewLine );
             WriteToJobLog( 'CHRGDSC: ' + %Trim(PCRSCG.CHRGDSC) + NewLine );
             WriteToJobLog( 'CHRGAMT: ' + %Char(PCRSCG.CHRGAMT) + NewLine );
             WriteToJobLog( '==========' + NewLine );
             reade UniqueID UPSPCRSCG.RUPSPCRSCG PCRSCG;
           enddo;

           reade UniqueID UPSPCRS.RUPSPCRS PCRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSPCRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSPCRQ` | **Record** Pickup Creation Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            RTPKUP         1A` | Rate Pickup Request **Valid Values:** `Y` |
| `A            CLSTIM          T` | Close Time |
| `A            RDYTIM          T` | Ready Time |
| `A            PKUPDT          L` | Pickup Date |
| `A            PCONAME       35A` | Pickup Company Name |
| `A            PCNNAME       35A` | Pickup Contact Name |
| `A            PADDR1        35A` | Pickup Address Line 1 |
| `A            PADDR2        35A` | Pickup Address Line 2 |
| `A            PADDR3        35A` | Pickup Address Line 3 |
| `A            PROOM          8A` | Pickup Room Number |
| `A            PFLOOR         3A` | Pickup Floor |
| `A            PCITY         40A` | Pickup City |
| `A            PSTATE         5A` | Pickup State |
| `A            PURBAN        50A` | Pickup Urbanization |
| `A            PPOSTCD       16A` | Pickup Postal Code |
| `A            PCNTRY         2A` | Pickup Country |
| `A            PRESDNT        1A` | Residential Address **Valid Values:** `Y` |
| `A            PPOINT        11A` | Pickup Point |
| `A            PPHONE        15A` | Pickup Phone Number |
| `A            PEXT          10A` | Pickup Phone Extention |
| `A            ALTADDR        1A` | Alternate Address Indicator |
| `A            TRACK1        18A` | Return Tracking Numbers |
| `A            TRACK2        18A` |  |
| `A            TRACK3        18A` |  |
| `A            TRACK4        18A` |  |
| `A            TRACK5        18A` |  |
| `A            TRACK6        18A` |  |
| `A            TRACK7        18A` |  |
| `A            TRACK8        18A` |  |
| `A            TRACK9        18A` |  |
| `A            TRACK10       18A` |  |
| `A            TRACK11       18A` |  |
| `A            TRACK12       18A` |  |
| `A            TRACK13       18A` |  |
| `A            TRACK14       18A` |  |
| `A            TRACK15       18A` |  |
| `A            TRACK16       18A` |  |
| `A            TRACK17       18A` |  |
| `A            TRACK18       18A` |  |
| `A            TRACK19       18A` |  |
| `A            TRACK20       18A` |  |
| `A            TRACK21       18A` |  |
| `A            TRACK22       18A` |  |
| `A            TRACK23       18A` |  |
| `A            TRACK24       18A` |  |
| `A            TRACK25       18A` |  |
| `A            TRACK26       18A` |  |
| `A            TRACK27       18A` |  |
| `A            TRACK28       18A` |  |
| `A            TRACK29       18A` |  |
| `A            TRACK30       18A` |  |
| `A            TOTWGT         7P 1` | Total Weight |
| `A            WGTCD          3A` | Weight Code |
| `A            LRGPKG         1A` | Large Package Indicator **Valid Values:** `T`, `Y` |
| `A            PAYMTHD        2A` | Payment Method |
| `A            INSTRCT       57A` | Special Instructions |
| `A            REFNBR        35A` | Customer-Assigned Reference Number |
| `A            CEMAIL1       59A` | Customer Emails |
| `A            CEMAIL2       59A` |  |
| `A            CEMAIL3       59A` |  |
| `A            CEMAIL4       59A` |  |
| `A            CEMAIL5       59A` |  |
| `A            UEMAIL        59A` | Undeliverable Email |
| `A            SVCCD          3A` | UPS Service Code |
| `A            QTY            3P 0` | Quantity of Packages |
| `A            DCNTRY         2A` | Destination Country |
| `A            CNTNRCD        2A` | Container Code |


### UPSPCRQTK.pf

| Field | Description |
|---|---|
| `A          R RUPSPCRQTK` | **Record** Pickup Creation Request Tracking Numbers |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            RTRACK        18A` | Return Tracking Number |


## Output Table Files

### UPSPCRS.pf

| Field | Description |
|---|---|
| `A          R RUPSPCRS` | **Record** Pickup Creation Request Response Data |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            REQNBR        11A` | Pickup Request Number |
| `A            RTCD           2A` | Rate Code |
| `A            RTDSC         35A` | Rate Code Description |
| `A            RTTYPE         2A` | Rate Type |
| `A            CURCD          3A` | Currency Code |
| `A            TOTTAX        10P 2` | Total Tax |
| `A            TOTCHRG       10P 2` | Total Charges |


### UPSPCRSCG.pf

| Field | Description |
|---|---|
| `A          R RUPSPCRSCG` | **Record** Pickup Creation Resonse Charge Data |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            CHRGCD         1A` | Charge Type Code |
| `A            CHRGDSC       30A` | Charge Description |
| `A            CHRGAMT       10P 2` | Charge Amount |
| `A            TAXAMT        10P 2` | Charge Tax Amount |



---

# UPS_pkupStatus()

> Checks UPS pickup pending status via the Pickup Pending Status API, reading from UPSPSRQ and writing results to UPSPSRS.

This subprocedure calls the UPS Pickup Pending Status API. It reads request data from UPSPSRQ, and writes response data to UPSPSRS.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_pkupStatus  PR              N

      // The ID of the record in UPSPSRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSPSRS.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_PS - Pickup Status Query

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the UPS_pkupStatus()
      *   subprocedure to query the status of a pickup request.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSPSRQ. Then, call
      *   UPS_pkupStatus(), passing in your unique ID as well as
      *   the other parameters shown.
      *
      *   UPS_pkupStatus() will return *On if no error was encountered, or
      *   *Off if an error occurred. If an error occurred, you should look at
      *   the fields in ErrorDS to retrieve information about the error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSPSRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSPSRQ   UF A E           K DISK    Qualified
     FUPSPSRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D PSRQ            DS                  LikeRec(UPSPSRQ.RUPSPSRQ:*Output)
     D PSRS            DS                  LikeRec(UPSPSRS.RUPSPSRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear PSRQ;
       PSRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       PSRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       PSRQ.AcctNbr = '523FE3';
       write UPSPSRQ.RUPSPSRQ PSRQ;

       // If UPS_pkupStatus() returns *Off, an error occurred and UPS_ErrorDS
       //  should be reviewed to determine the cause.
       if not UPS_pkupStatus( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSPSRS.RUPSPSRS;
         if not %Found(UPSPSRS);
           WriteToJobLog( 'ERROR: No results found in UPSPSRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSPSRS. A selection of the available fields
         //  is output by the example program, but more are available - review
         //  the file to see what else is available.
         reade UniqueID UPSPSRS.RUPSPSRS PSRS;
         dow not %Eof(UPSPSRS);
           WriteToJobLog( 'Result Record:' + NewLine );
           WriteToJobLog( 'PID: ' + %Char(PSRS.PID) + NewLine );
           WriteToJobLog( 'UID: ' + %Char(PSRS.UID) + NewLine );
           WriteToJobLog( 'PKTYPE: ' + PSRS.PKTYPE + NewLine );
           WriteToJobLog( 'SVCDT: ' + %Char(PSRS.SVCDT) + NewLine );
           WriteToJobLog( 'PRN: ' + PSRS.PRN + NewLine );
           WriteToJobLog( 'STSMSG: ' + PSRS.STSMSG + NewLine );
           reade UniqueID UPSPSRS.RUPSPSRS PSRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSPSRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSPSRQ` | **Record** Pickup Status Request |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |


## Output Table Files

### UPSPSRS.pf

| Field | Description |
|---|---|
| `A          R RUPSPSRS` | **Record** Pickup Status Response |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            PKTYPE         2A` | Pickup Type |
| `A            SVCDT           L` | Service Date |
| `A            PRN           11A` | Pickup Request Number |
| `A            GWNSTS         2A` | GWN Status Code |
| `A            STSCD          3A` | On-Call Status Code |
| `A            STSMSG       500A` | Pickup Status Message |
| `A            BILLCD         2A` | Billing Code |
| `A            CNNAME        35A` | Contact Name |
| `A            REFNBR        35A` | Pickup Reference Number |



---

# UPS_pkupCancel()

> Cancels a scheduled UPS pickup via the Pickup Cancel API, reading from UPSPXRQ and writing results to UPSPXRS.

This subprocedure calls the UPS Pickup Cancel API. It reads in request data from UPSPXRQ and writes response data to UPSPXRS.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_pkupCancel  PR              N

      // The ID of the record in UPSPXRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSPXRS.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_PX - Pickup Cancellation

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the UPS_pkupCancel()
      *   subprocedure to cancel a pickup request.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSPXRQ. Then, call
      *   UPS_pkupCancel(), passing in your unique ID as well as
      *   the other parameters shown.
      *
      *   UPS_pkupCancel() will return *On if no error was encountered, or
      *   *Off if an error occurred. If an error occurred, you should look at
      *   the fields in ErrorDS to retrieve information about the error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSPXRS physical
      *   file, and retrieve the result fields.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSPXRQ   UF A E           K DISK    Qualified
     FUPSPXRS   IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D PXRQ            DS                  Likerec(UPSPXRQ.RUPSPXRQ:*Output)
     D PXRS            DS                  Likerec(UPSPXRS.RUPSPXRS:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear PXRQ;
       PXRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       PXRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       PXRQ.AcctNbr = '523FE3';
       // This specifies that we are cancelling by Pickup Request Number (PRN)
       PXRQ.CnlBy = '02';
       // This must be a valid Pickup Request Number
       PXRQ.PRN = 'a1234567890';
       write UPSPXRQ.RUPSPXRQ PXRQ;

       // If UPS_pkupCancel() returns *Off, an error occurred and UPS_ErrorDS
       //  should be reviewed to determine the cause.
       if not UPS_pkupCancel( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSPXRS.RUPSPXRS;
         if not %Found(UPSPXRS);
           WriteToJobLog( 'ERROR: No results found in UPSPXRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSPXRS. A selection of the available fields
         //  is output by the example program, but more are available - review
         //  the file to see what else is available.
         reade UniqueID UPSPXRS.RUPSPXRS PXRS;
         dow not %Eof(UPSPXRS);
           WriteToJobLog( 'Result Record:' + NewLine );
           WriteToJobLog( 'UID: ' + %Char(PXRS.UID) + NewLine );
           WriteToJobLog( 'PKTYPE: ' + PXRS.PKTYPE + NewLine );
           reade UniqueID UPSPXRS.RUPSPXRS PXRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;
      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSPXRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSPXRQ` | **Record** Pickup Cancel Request Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            PRN           11A` | Pickup Request Number |
| `A            CNLBY          2A` | Cancel By **Valid Values:** `01`, `02` |


## Output Table Files

### UPSPXRS.pf

| Field | Description |
|---|---|
| `A          R RUPSPXRS` | **Record** Pickup Cancel Response Record |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            PKTYPE         2A` | Pickup Type |
| `A            GWNCD          3A` | GWN Code |
| `A            GWNDSC       150A` | GWN Description |



---

# UPS_pkupRating()

> Retrieves UPS pickup rates via the Pickup Rate API, reading from UPSPRRQ and writing rate and charge data to UPSPRRS/UPSPRRSCG.

This subprocedure calls the UPS Pickup Rate API. It reads in request data from UPSPRRQ, and writes response data to UPSPRRS and charge data to UPSPRRSCG.

## Subprocedure Prototype

```rpgle
      // Returns *OFF if an error occurs during processing, *ON otherwise.
     D UPS_pkupRating  PR              N

      // The ID of the record in UPSPRRQ that will be used to build the request,
      //   and under which the response data will be saved in UPSPRRS and
      //   UPSPRRSCG.
     D  pUniqueID                    15P 0

      // The data structure in which error information will be returned.
     D  pErrorDS                           LikeDS(UPS_Error)
```


## Example Code

### T_PR - Pickup Rating

```rpgle
      *------------------------------------------------------------------------
      * @Author: Kato Integrations
      * @Description:
      *   This is a test program to illustrate how to call the
      *   UPS_pkupRating() subprocedure to rate a pickup.
      *
      *   To achieve this, generate a unique ID with UPS_getUID(), and
      *   then populate and write a record to UPSPRRQ. Then, call
      *   UPS_pkupRating() passing in your unique ID as well as the other
      *   parameters shown.
      *
      *   UPS_pkupRating() will return *On if no error was encountered,
      *   or *Off if an error occurred. If an error occurred, you should
      *   look at the fields in ErrorDS to retrieve information about the
      *   error.
      *
      *   Otherwise, you can perform a CHAIN against the UPSPRRS physical
      *   file, and retrieve the result fields, as well as child records
      *   from UPSPRRSCG to view details about individual charges.
      *------------------------------------------------------------------------
     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('UPSBND') OPTION(*NODEBUGIO)

     FUPSPRRQ   UF A E           K DISK    Qualified
     FUPSPRRS   IF A E           K DISK    Qualified
     FUPSPRRSCG IF A E           K DISK    Qualified

      /COPY QRPGLECPY,UPS

      // This is included for demo output purposes.
     D WriteToJobLog   PR            10I 0 Extproc('Qp0zLprintf')
     D  pString                        *   Value Options(*String)
     D NewLine         C                   x'15'

     D PRRQ            DS                  Likerec(UPSPRRQ.RUPSPRRQ:*Output)
     D PRRS            DS                  Likerec(UPSPRRS.RUPSPRRS:*Input)
     D PRRSCG          DS                  Likerec(UPSPRRSCG.RUPSPRRSCG:*Input)

     D ErrorDS         DS                  LikeDS(UPS_ErrorDS_t) Inz(*LikeDS)

     D UniqueID        S                   Like(UPS_UniqueID_t)
      /FREE
       reset ErrorDS;

       // Retrieve Unique ID used to identify this request
       UniqueID = UPS_getUID();

       clear PRRQ;
       PRRQ.UID = UniqueID;
       // Populate this field with application name set up using WRKUPSAUTH
       PRRQ.UserID = 'KATO_TEST';
       // Populate this field with a UPS account number configured in
       //  file UPSCFGACCT
       PRRQ.AcctNbr = '523FE3';

       PRRQ.PADDR1 = '4706 Chiquita Blvd S';
       PRRQ.PCITY = 'Cape Coral';
       PRRQ.PSTATE = 'FL';
       PRRQ.PPOSTCD = '33914';
       PRRQ.PCNTRY = 'US';
       PRRQ.PRESDNT = 'N';
       PRRQ.ALTADDR = 'Y';
       PRRQ.DTOPT = '03';

       PRRQ.CLSTIM = %Time() + %Hours(6);
       PRRQ.RDYTIM = %Time() + %Hours(2);
       PRRQ.PKUPDT = %Date() + %Days(1);

       write UPSPRRQ.RUPSPRRQ PRRQ;

       // If UPS_pkupRating() returns *Off, an error occurred and
       //  UPS_ErrorDS should be reviewed to determine the cause.
       if not UPS_pkupRating( UniqueID : ErrorDS );
         WriteToJobLog( 'API Error: ' + NewLine );
         WriteToJobLog( 'Error Code: ' + %Trim(ErrorDS.Code) + NewLine );
         WriteToJobLog( 'Error Severity: ' +
                        %Char(ErrorDS.Severity) + NewLine );
         WriteToJobLog( 'Error Source: ' + %Trim(ErrorDS.Pgm) + NewLine );
         WriteToJobLog( 'Error Text: ' + %Trim(ErrorDS.Text) + NewLine );
         exsr cleanup;
         return;
       else;
         setll UniqueID UPSPRRS.RUPSPRRS;
         if not %Found(UPSPRRS);
           WriteToJobLog( 'ERROR: No results found in UPSPRRS' + NewLine );
           exsr cleanup;
           return;
         endif;

         // Read the results from UPSPRRS. A selection of the available fields
         //  is output by this example program but more are availble - review
         //  the file to see what else is available.
         reade UniqueID UPSPRRS.RUPSPRRS PRRS;
         dow not %Eof(UPSPRRS);
           WriteToJobLog( 'Result Record: ' + NewLine );
           WriteToJobLog( 'UID: ' + %Char(PRRS.UID) + NewLine );
           WriteToJobLog( 'RTTYPE: ' + %Trim(PRRS.RTTYPE) + NewLine );
           WriteToJobLog( 'CURCD: ' + %Trim(PRRS.CURCD) + NewLine );
           WriteToJobLog( 'TOTTAX: ' + %Char(PRRS.TOTTAX) + NewLine );
           WriteToJobLog( 'TOTCHRG: ' + %Char(PRRS.TOTCHRG) + NewLine );

           // Read through UPSSCRSPG for package-level charges. Depending on
           //  your request, there may not be any.
           chain UniqueID UPSPRRSCG.RUPSPRRSCG PRRSCG;
           if not %Found(UPSPRRSCG);
             WriteToJobLog( 'ERROR: No results found in UPSPCRSCG' + NewLine );
             exsr cleanup;
             return;
           endif;

           dow not %Eof(UPSPRRSCG);
             WriteToJobLog( 'Child Result Record: ' + NewLine );
             WriteToJobLog( 'PID: ' + %Char(PRRSCG.PID) + NewLine );
             WriteToJobLog( 'UID: ' + %Char(PRRSCG.UID) + NewLine );
             WriteToJobLog( 'CHRGCD: ' + %Trim(PRRSCG.CHRGCD) + NewLine );
             WriteToJobLog( 'CHRGDSC: ' + %Trim(PRRSCG.CHRGDSC) + NewLine );
             WriteToJobLog( 'CHRGAMT: ' + %Char(PRRSCG.CHRGAMT) + NewLine );
             WriteToJobLog( 'TAXAMT: ' + %Char(PRRSCG.TAXAMT) + NewLine );
             WriteToJobLog( '==========' + NewLine );
             reade UniqueID UPSPRRSCG.RUPSPRRSCG PRRSCG;
           enddo;

           reade UniqueID UPSPRRS.RUPSPRRS PRRS;
         enddo;
       endif;

       exsr cleanup;
       return;

       begsr cleanup;
         // Always call UPS_cleanup() any time your program will terminate
         UPS_cleanup();
         *INLR = *ON;
       endsr;

      /END-FREE
```

## Data Structures

### UPS_Error

```rpgle
     D UPS_Error       DS                  Qualified Inz

      // Error code raised by subprocedure
     D  Code                         10A

      // Severity of error - will be either UPS_SEVERE or UPS_INFO
     D  Severity                     10I 0

      // Name of subprocedure that raised the error
     D  Pgm                          30A   Varying

      // Error message text
     D  Text                      32000A   Varying
```


## Input Table Files

### UPSPRRQ.pf

| Field | Description |
|---|---|
| `A          R RUPSPRRQ` | **Record** Pickup Rating Request |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            USERID        30A` | UPS User ID |
| `A            ACCTNBR       10A` | UPS Account Number |
| `A            PADDR1        35A` | Pickup Address Line 1 |
| `A            PADDR2        35A` | Pickup Address Line 2 |
| `A            PADDR3        35A` | Pickup Address Line 3 |
| `A            PCITY         40A` | Pickup City |
| `A            PSTATE         5A` | Pickup State or Province |
| `A            PPOSTCD       16A` | Pickup Postal Code |
| `A            PCNTRY         2A` | Pickup Country Code |
| `A            PRESDNT        1A` | Pickup Residental Address Indicator |
| `A            ALTADDR        1A` | Alternate Address Indicator |
| `A            DTOPT          2A` | Service Date Option |
| `A            CLSTIM          T` | Close Time |
| `A            RDYTIM          T` | Ready Time |
| `A            PKUPDT          L` | Pickup Date |


## Output Table Files

### UPSPRRS.pf

| Field | Description |
|---|---|
| `A          R RUPSPRRS` | **Record** Pickup Rating Response Data |
| `A            UID           15P 0` | **Key** Record Unique ID |
| `A            RTTYPE         2A` | Rate Type |
| `A            CURCD          3A` | Currency Code |
| `A            TOTTAX        10P 2` | Total Tax |
| `A            TOTCHRG       10P 2` | Total Charges |


### UPSPRRSCG.pf

| Field | Description |
|---|---|
| `A          R RUPSPRRSCG` | **Record** Pickup Rating Response Data - Charge Information |
| `A            PID           15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            CHRGCD         1A` | Charge Type Code |
| `A            CHRGDSC       30A` | Charge Description |
| `A            CHRGAMT       10P 2` | Charge Amount |
| `A            TAXAMT        10P 2` | Tax Amount |



---

# UPS_cleanup()

> Closes all open UPS physical files; should be called before program termination to release file resources.

This subprocedure closes all open UPS* physical files, and should be called before your program terminates.

## Subprocedure Prototype

```rpgle
     D UPS_cleanup     PR
```



---

# UPS_getUID()

> Retrieves the next unique ID from data area UPSUNQ for use as a request identifier.

This subprocedure retrieves the next unique ID from data area UPSUNQ.

## Subprocedure Prototype

```rpgle
      // Returns a unique ID, to be used in UPS transactions.
     D UPS_getUID      PR            15P 0
```



---

# UPS_log()

> Writes a message or error entry to the UPSLOG physical file for audit and debugging purposes.

This subprocedure logs messages and errors to physical file UPSLOG.

## Subprocedure Prototype

```rpgle
     D UPS_log         PR

      // This value is used to retrieve configuration information.
     D  pUniqueID                    15P 0 Value

      // The name of the subprocedure which generated the message.
     D  pProgramName                 30A   Value

      // The logging level of the message.
      // Valid values: UPS_SEVERE, UPS_WARNING, UPS_INFO
     D  pSeverity                     3P 0 Value

      // The content of the message, to be written to the UPSLOG file.
     D  pMessage                   1024A   Value
```


## Output Table Files

### UPSLOG.pf

| Field | Description |
|---|---|
| `A          R RUPSLOG` | **Record** Logging Record |
| `A            PID          15P 0` | **Key** Parent Unique ID |
| `A            UID           15P 0` | **Key** Child Unique ID |
| `A            PGMNAME       30A` | Program Name |
| `A            TMSTMP          Z` | Log Timestamp |
| `A            SEVERITY       3P 0` | Message Severity |
| `A            MESSAGE     1024A` | Log Message |



---

# Work with UPS Authentication (WRKUPSAUTH)

> Configures UPS OAuth credentials (Client ID and Client Secret) in UPSTI, assigns them to named configurations, and selects CIE or production endpoints per API.

Your UPS Toolkit for i installation will need to be configured to access the UPS APIs. This requires you to provide UPS API credentials, known as your `Client ID` and `Client Secret`. The `Client ID` and `Client Secret` are provided to you by UPS.

**NOTE:** The `Client ID` and `Client Secret` are different from your username and password used to access the UPS website, and different from the UPS access key which UPS APIs previously used for authentication.

You will assign your `Client ID` and `Client Secret` a name, and optionally a description. The name can be anything you want, but it must match the value you set for the `USERID` fields in request tables prior to calling UPS APIs.

You will also need to configure whether your API requests will be performed against the UPS "Customer Integration Environment" endpoints (used for testing and development), or the UPS "Production" endpoints, which use live UPS data, and any shipments created will incur charges. Which endpoint to use can be configured on a per API basis.

To begin configuration, ensure your UPSTI library is in your library list, and run the `WRKUPSAUTH` command. You should see a screen similar to the below image:

![Work with UPS Authentication (WRKUPSAUTH)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/main.png "Work with UPS Authentication (WRKUPSAUTH)")

Next, press **F6** to **Create** a new application, which will present you with the following screen:

![Work with UPS Authentication (WRKUPSAUTH)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/create.png "Work with UPS Authentication (WRKUPSAUTH)")

To create an application, you need to provide a name, the Client ID, and the Client Secret. You can optionally provide a description.

You should also review which environment you wish to use for each API. An environment must be set to `*CIE` to use the UPS Customer Integration Environment, or `*PROD` to use the UPS Production environment. By default, Address Validation, Rating, Time in Transit, and Tracking are set to `*PROD` as these APIs only retrieve information from UPS. The other APIs are set to `*CIE` by default as they will initiate actions and may cause you to incur charges if the API is called using the UPS Production environment.

![Work with UPS Authentication (WRKUPSAUTH)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/create2.png "Work with UPS Authentication (WRKUPSAUTH)")

Once you have finished your configuration, press Enter, and when prompted to confirm, type **Y**. You should be returned to the list view and see your newly created record.

![Work with UPS Authentication (WRKUPSAUTH)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/main2.png "Work with UPS Authentication (WRKUPSAUTH)")

Aside from creating a new record, you can use the provided options to Edit, Copy, Delete, Display, or Rename. For example, using option 5 to Display the record we just created will show the following screen:

![Work with UPS Authentication (WRKUPSAUTH)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/display.png "Work with UPS Authentication (WRKUPSAUTH)")

This screen shows the status of what are referred to as your **CIE Token** and **Production Token**. These tokens are retrieved from UPS using your `Client ID` and `Client Secret`, and are used to authenticate you to the UPS APIs. These tokens automatically expire after a period of time set by UPS. UPSTI will handle requesting and renewing these tokens (if needed) each time you call one of the UPS APIs.

---

# Apply License (APYLIC)

> Applies a permanent or temporary license key to the UPS Toolkit for i installation.

To apply a permanent or temporary license key, you will use the included command APYLIC. Your license key will typically be supplied via email in a command string:

`APYLIC LICKEY(2C5AAA363DD993F8AADFB45730AB6A5D) PRODUCT(UPSTI)`

Or, you can copy and paste the received key into the command:

![Apply License (APYLIC)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/apylic.png "Apply License (APYLIC)")

After running the APYLIC command, you should receive a message that says **License applied successfully**

If you don't receive that message, or receive an error message, please contact us at <a href="mailto:isupport@katointegrations.com">isupport@katointegrations.com</a>.

---

# Display License (DSPLIC)

> Displays system machine information and license key status required by support to generate activation keys.

DSPLIC is used to retrieve system information as well as license status.

**Note:** [Display Machine Info (DSPMCHINF)](https://isupport.katointegrations.com/upsti/2.x/dspmchinf.md) is an alias for this command. These commands may be used interchangeably.

The command does not have any parameters:

`DSPLIC`

The command should display a screen similar to the one below. This screen indicates all the information necessary to generate your license key, as well as the current status of any applied license keys.

![Display License (DSPLIC)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/dsplic.png "Display License (DSPLIC)")

If you don't receive that message or receive an error message, please contact us at <a href="mailto:isupport@katointegrations.com">isupport@katointegrations.com</a>.

---

# Display Machine Info (DSPMCHINF)

> Alias for DSPLIC; displays machine and license information needed for activation key generation.

DSPMCHINF is used to retrieve system information as well as license status.

**Note:** DSPMCHINF is an alias for the [Display License (DSPLIC)](https://isupport.katointegrations.com/upsti/2.x/dsplic.md) command. These commands may be used interchangeably.

The command does not have any parameters:

`DSPMCHINF`

The command should display a screen similar to the one below. This screen indicates all the information necessary to generate your license key, as well as the current status of any applied license keys.

![Display Machine Info (DSPMCHINF)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/dspmchinf.png "Display Machine Info (DSPMCHINF)")

If you don't receive that message or receive an error message, please contact us at <a href="mailto:isupport@katointegrations.com">isupport@katointegrations.com</a>.

---

# Display Version (DSPVER)

> Displays the currently installed version of UPS Toolkit for i.

DSPVER can be used to retrieve the version number of the currently installed product.

The command does not have any parameters:

`DSPVER`

You should receive a message indicating the currently installed version as well as the library in which the product is installed.

![Display Version (DSPVER)](https://isupport.katointegrations.com/llms/ups-toolkit-for-i-2.x/dspver.png "Display Version (DSPVER)")

If you don't receive that message or receive an error message, please contact us at <a href="mailto:isupport@katointegrations.com">isupport@katointegrations.com</a>.
