Skip to content

Commit

Permalink
v1.0.0 deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
hwjeremy committed Nov 29, 2023
1 parent 2ac6542 commit 3d4decf
Show file tree
Hide file tree
Showing 14 changed files with 817 additions and 40 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
**/procuret.js
**/procuret.js
.DS_Store
**/test.html
*.pyc
207 changes: 204 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,205 @@
# Procuret JavaScript Library
# Introduction

This library provides JavaScript types for interacting with the Procuret
API.
Procuret API JavaScript (PJS) allows you to perform Procuret API operations in
JavaScript code. Its only dependency is a "typical" browser-like environment.
That is, it must run in an environment that has browser-like APIs available,
such as `XMLHTTPRequest`.

PJS is provided as raw JavaScript files which you can manually package as you
see fit. For example, you might copy and paste relevant files for your use
case and include them in your software. You can also use included Python tools
to package PJS for include in HTML documents or for provision via a web server.
(See "Packaging Tools" below.)

Tests are provided for verification of functionality.

## Versioning and public interfaces

PJS follows [Semantic Versioning](https://semver.org) conventions. At any time,
the repository may included an undocumented type in the `source` directory.
These types should be considered unavailable and their function is not
guaranteed.

# Available Types

## `PR_ProspectivePayment`

A theoretical payment amount, and the number of months over which that payment
would be made, if an applicant successfully applied for a Procuret Instalment
Plan.

### Properties

- `.periods` - `Number` - The number of months over which payment would be made
- `.amount` - `PR_Amount` - The monthly payment amount
- `.supplierId` - `String` - The ID of the Procuret supplier for which this
price is valid.

### Static Methods

#### .retrieve

Retrieve a single `PR_ProspectivePayment` for given parameters. To use this
method, you must know a valid `months` value in advance. If you don't know
a valid `months` value in advance, prefer `.retrieveAllAvailable`.

##### Parameters

1. `callback` - `Function<Error?, PR_ProspectivePayment?>` - A function taking
optional error and result parameters, in which you can handle the API response.
2. `principal` - `String` - A string-encoded number representing the principal
value of the prospective loan. For example, a total invoice value. Minimum
value `500` currency units.
3. `supplierId` - `String` - Your Supplier ID. Consult your Procuret
partnership manager if you are unsure of this value.
4. `denomination` - `PR_Currency` - The monetary denomination of the `principal`
value.
5. `months` - `Number` - The integer number of months over which the instalment
plan would be paid.
6. `endpoint` - `Optional<String>` - Optionally override the API endpoint.
Useful in testing a demonstration environments.
7. [undocumented, do not use, do not provide a value]

##### Example Usage

```javascript
PR_ProspectivePayment.retrieve(
(error, prospectivePayment) => {

if (error) { console.log('An error occurred'); return; }

console.log('A successful applicant would pay \
' + payment.amount.asDenominatedString + ' per month');

return;

},
"600", // $600
"511291212", // some Supplier ID
PR_Currency.AUD, // Australian dollars
12 // 12 months
);
```

#### .retrieveAllAvailable

Retrieve all available `PR_ProspectivePayment` for given parameters. This is
a convenient way to display all potential instalment plan payment amounts to
a potential applicant.

##### Parameters

1. `callback` - `Function<Error?, PR_ProspectivePayment?>` - A function taking
optional error and result parameters, in which you can handle the API response.
2. `principal` - `String` - A string-encoded number representing the principal
value of the prospective loan. For example, a total invoice value. Minimum
value `500` currency units.
3. `denomination` - `PR_Currency` - The monetary denomination of the `principal`
value.
4. `supplierId` - `String` - Your Supplier ID. Consult your Procuret
partnership manager if you are unsure of this value.
5. `endpoint` - `Optional<String>` - Optionally override the API endpoint.
Useful in testing a demonstration environments.
6. [undocumented, do not use, do not provide a value]

##### Example Usage

```javascript
PR_ProspectivePayment.retrieveAllAvailable(
(error, availablePayments) => {

if (error) { console.log('An error occurred'); return; }

const availablePayments = payments.map((p) => {
return p.amount.asDenominatedString
});

console.log('Applicants may choose from the following payments \
' + availablePayments);

return;

},
"600", // $600
PR_Currency.AUD, // Australian dollars
"511291212", // some Supplier ID
12 // 12 months
);
```
---
## `PR_Currency`

A unit of monetary denomination

### Properties

- `iso_4217` - `String` - The ISO 4217 code of this currency
- `symbol` - `String` - The common-use symbol for this currency
- `exponent` - `Number` - The integer exponent of the currency's subunits
- `name` - `String` - The full-form name of this currency
- `indexid` - `Number` - A unique integer identifier for the currency in the
Procure context

### Static Properties

- `.AUD` - `PR_Currency` - Australian dollars
- `.NZD` - `PR_Currency` - New Zealand dollars
- `.allAvailable` - `Array<PR_Currency>` - All available currencies

---
## `PR_Amount`

A monetary amount, a combination of magnitude and currency denomination

### Properties

- `asNumber` - `Number` - The amount magnitude cast to a JavaScript `Number`
- `asLocaleString` - `String` - A Locale-defined string representation
- `asSymbolisedString` - `String` - The amount prefixed by its currency symbol
- `asDenominatedString` - `String` - The amount prefixed by its ISO 4217 code
- `magnitude` - `String` - The undenominated magnitude of the amount
- `denomination` - `PR_Currency` - The denomination of the amount
- `isGreaterThanZero` - `Boolean` - `true` if the magnitude of the amount is
greater than zero, else `false`


# Packaging Tools

PJS includes built in Python tools for packaging. To compile the entire PJS
library into a single JavaScript file, invoke the following Python commands
from the `tools` directory:

```bash
$ cd tools
$ python3 compile.py
```

A `procuret.js` file will appear in the `tools` directory.

# Running Tests

PJS includes a built in test GUI. To run the tests, first compile the test
tool:

```bash
$ cd tools
$ python3 compile_tests.py
```

A `test.html` document will appear in the `tools` directory. Serve `test.html`
from a web server, and then interact with the tool via a web browser. For
example, you can locally serve the tools directory using...

```bash
$ python3 -m http.server
```

... Whereupon the test tool is available at http://127.0.0.1:8000/test.html.

Note that you cannot open `test.html` in your browser from the file system
with a modern security-standards-compliant browser. All tests will fail due to browser's Cross-Origin-Resource-Sharing requirements being unmet.

# Get Help

To get help integrating PJS into your software, write to your Procuret
partnership manager, or write to our team at [email protected].
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.3
1.0.0
67 changes: 67 additions & 0 deletions source/ancillary/amount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* Procuret API JS - Amount JS Class */


class PR_Amount {

constructor(
magnitude, // String decimal number e.g. "4,000" or "4000"
currency // PR_Currency
) {

if (!currency) { throw Error('Cannot init w/ falsey PR_Currency'); }

this._magnitude = magnitude;
this._currency = currency;

return;
}

get asNumber() { return new Number(this._magnitude); }
get asLocaleString() {
return this.asNumber.toLocaleString(undefined, {
minimumFractionDigits: this._currency.exponent
});
}
get asSymbolisedString() {
return this._currency.symbol + this.asLocaleString;
}
get asDenominatedString() {
return this._currency.iso_4217 + ' ' + this.asLocaleString;
}

get magnitude() { return this._magnitude; }
get denomination() { return this._currency; }

get isGreaterThanZero() { return Number(this._magnitude) > 0; }

rounded(decimalPlaces) {
return new PR_Amount(
Number(this._magnitude).toFixed(decimalPlaces),
this._currency
);
}

magnitudeIsGreaterThan(value) {
return Number(this._magnitude) > value;
}

encode() {
return {
'magnitude': this._magnitude,
'denomination': this._currency.indexid
}
}

static decode(data) {
return new PR_Amount(
data['magnitude'],
PR_Currency.decode(data['denomination'])
);
}

static optionallyDecode(data) { // -> Optional<Self>
if (!data) { return null; }
return PR_Amount.decode(data);
}

}
81 changes: 81 additions & 0 deletions source/ancillary/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* Procuret JS - API error class */

const PR_ERROR_INFO_KEY = 'error-information';
const PR_ERROR_CUSTOMER_INFORMATION = {
400: "Procuret's servers could not understand the information sent by \
your device. This likely indicates a bug in our application. Our support \
team has been notified automatically, but please feel free to contact \
us at [email protected]",
500: "Procuret's servers encountered an error when processing information \
sent by your device. There may be a bug in our systems, or they may be \
experiencing a temporary service disruption. Our support team has been \
notified automatically.",
503: "Procuret's servers encountered a service disruption while processing \
your request. This error may disappear if you try again in a few moments. \
Our support team has been notified automatically. If this error persists, \
please write to us at [email protected].",
401: "Procuret's servers could not identify you when processing \
data sent by your device. This likely indicates a bug has crept into \
our application. Please contact us at [email protected].",
403: "You don't appear to be authorised to perform the action you \
were attempting. This likely indicates a bug has crept into \
our application. Please contact us at [email protected].",
429: "Procuret's servers have noticed unusually high activity levels \
from your device or the network it is connected to. Please try again in \
few minutes. If you continue to see this message, please contact \
[email protected]",
404: "Procuret's servers were unable to find a resource needed to \
serve your request. This likely indicates a bug in our application. Our \
support team has been notified automatically, but please feel free to \
contact us at [email protected]",
422: "Procuret was unable to process your request, due to a problem with \
the information sent by your device."
}
const PR_ERROR_FALLBACK_INFORMATION = "Procuret has encountered an error. There \
may be a bug in our systems, or they may be experiencing a temporary \
disruption. We will \
attempt to resolve the problem as quickly as possible";

class PR_ApiError extends Error {

static get genericDescription() { return PR_ERROR_FALLBACK_INFORMATION; }

constructor(
code, // Integer
data=null, // Optional<Object>
requestSummary=null // Optional<Object> (Untyped)
) {

const description = PR_ERROR_CUSTOMER_INFORMATION[code];
let techInfo = (() => {
if (code != 0) { return 'Generic ' + String(code); }
return 'Client side error';
})();
if (
typeof(data) != 'undefined'
&& data != null
&& data[PR_ERROR_INFO_KEY]
) {
techInfo = data[PR_ERROR_INFO_KEY];
}
const logMessage = 'API error (' + code + '), ' + techInfo;
super(logMessage);

const self = this;

self._code = code;
self._customerDescription = description
|| PR_ERROR_FALLBACK_INFORMATION;
self._technicalDescription = techInfo;
self._requestSummary = requestSummary;

return

}

get code() { return this._code }
get customerDescription() { return this._customerDescription }
get technicalDescription() { return this._technicalDescription }


}
4 changes: 2 additions & 2 deletions source/ancillary/query_string.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* Procuret JS - QueryString */

class PR_UrlQueryString {
class PR_QueryString {

constructor(
url_parameters // Array<PR_UrlParameter>
url_parameters // Array<PR_QueryTerm>
) {

if (url_parameters.length === undefined) {
Expand Down
Loading

0 comments on commit 3d4decf

Please sign in to comment.