First pre-Beta version of pmtservice is completed
This commit is contained in:
parent
ee539f66a6
commit
24bbbbab72
10 changed files with 378 additions and 8 deletions
BIN
AccountingIntegration.odt
Normal file
BIN
AccountingIntegration.odt
Normal file
Binary file not shown.
BIN
AccountingIntegration.pdf
Normal file
BIN
AccountingIntegration.pdf
Normal file
Binary file not shown.
|
@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- First testing version of pmtservice for Xero accounting is running
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added new service for Xero integration
|
- Added new service for Xero integration
|
||||||
|
|
BIN
CurrencyCodes.ods
Normal file
BIN
CurrencyCodes.ods
Normal file
Binary file not shown.
|
@ -0,0 +1,24 @@
|
||||||
|
.invoice {
|
||||||
|
font-family: Roboto Mono !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zecSign {
|
||||||
|
margin-bottom: -4px;
|
||||||
|
font-size: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoiceHeader {
|
||||||
|
display: flex;
|
||||||
|
font-family: Spartan;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 26px;
|
||||||
|
color: white;
|
||||||
|
justify-content: space-between;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 10px;
|
||||||
|
vertical-align: center;
|
||||||
|
max-width: 600px;
|
||||||
|
background: #ff5722;
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,163 @@
|
||||||
<p>{{ pmtData.ownerId }}</p>
|
<div style="font-family: 'Spartan';
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;">
|
||||||
|
<div class="container">
|
||||||
|
<div class="invoiceHeader">
|
||||||
|
<img class="logo" src="/assets/logo-new-white.png" height="40px" />
|
||||||
|
</div>
|
||||||
|
<div *ngIf="reportType==1">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Invalid Owner ID!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="reportType==2">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Payment service not<br>
|
||||||
|
enabled for<br>
|
||||||
|
{{ owner.name}}
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==3">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Connection to Xero<br>server failed!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==4">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Invoice<br>{{ pmtData.invoice }}<br>not found!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==5">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Invoice<br>{{ pmtData.invoice }}<br>type invalid!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==6">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Invoice <br>{{ pmtData.invoice }}<br>already paid!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==7">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Currency <br>[ {{ pmtData.currency }} ]<br>not supported!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==8">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Amount does not<br>
|
||||||
|
match value<br>
|
||||||
|
reported by Xero!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="reportType==0">
|
||||||
|
<div style="height: 50px;">
|
||||||
|
</div>
|
||||||
|
<div style="font-weight: 700;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: center;">
|
||||||
|
Invoice Goes here!!!
|
||||||
|
</div>
|
||||||
|
<div style="height: 40px;">
|
||||||
|
</div>
|
||||||
|
Payment request was not processed!!
|
||||||
|
<div style="height: 20px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<p>Owner = {{ pmtData.ownerId }}</p>
|
||||||
|
<p>Owner ID = xxxx</p>
|
||||||
|
<p>Type = {{ inv_Type }}</p>
|
||||||
|
<p>Invoice ID = {{ inv_Id }}</p>
|
||||||
|
<p>Invoice No = {{ inv_No }}</p>
|
||||||
|
<p>Contact = {{ inv_Contact }}</p>
|
||||||
|
<p>Currency = {{ inv_Currency }}</p>
|
||||||
|
<p>Total = {{ inv_Total }}</p>
|
||||||
|
<p>Date = {{ inv_Date }}</p>
|
||||||
|
<p>Status = {{ inv_Status }}</p>
|
||||||
|
<p>Short Code = {{ invData.inv_shortCode }}</p>
|
||||||
|
<p>Process Date = {{ invData.inv_ProcDate }}</p>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,6 +1,14 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Router, ActivatedRoute, Params } from "@angular/router";
|
import { Router, ActivatedRoute, Params } from "@angular/router";
|
||||||
import { PmtData } from "./pmtservice.model"
|
import { HttpClient, HttpParams, HttpHeaders } from "@angular/common/http";
|
||||||
|
import { PmtData } from "./pmtservice.model";
|
||||||
|
import { XeroInvoice } from "./xeroinvoice.model";
|
||||||
|
import { Owner } from '../owner.model';
|
||||||
|
import { ConfigData } from '../configdata';
|
||||||
|
import { Item } from '../items/item.model'
|
||||||
|
|
||||||
|
var Buffer = require('buffer/').Buffer;
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pmtservice',
|
selector: 'app-pmtservice',
|
||||||
|
@ -10,6 +18,8 @@ import { PmtData } from "./pmtservice.model"
|
||||||
|
|
||||||
export class PmtserviceComponent implements OnInit {
|
export class PmtserviceComponent implements OnInit {
|
||||||
|
|
||||||
|
beUrl = ConfigData.Be_URL;
|
||||||
|
private reqHeaders: HttpHeaders = new HttpHeaders();
|
||||||
|
|
||||||
public pmtData : PmtData = {
|
public pmtData : PmtData = {
|
||||||
ownerId :'',
|
ownerId :'',
|
||||||
|
@ -19,17 +29,173 @@ export class PmtserviceComponent implements OnInit {
|
||||||
shortcode: ''
|
shortcode: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private activatedRoute: ActivatedRoute) {}
|
public invData : XeroInvoice = {
|
||||||
|
inv_Type : '',
|
||||||
|
inv_Id : '',
|
||||||
|
inv_No : '',
|
||||||
|
inv_Contact : '',
|
||||||
|
inv_Currency : '',
|
||||||
|
inv_CurrencyRate : 0,
|
||||||
|
inv_Status : '',
|
||||||
|
inv_Total : 0,
|
||||||
|
inv_Date : new Date(),
|
||||||
|
inv_shortCode : '',
|
||||||
|
inv_ProcDate : new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
public owner: Owner = {
|
||||||
|
address: '',
|
||||||
|
name: '',
|
||||||
|
currency: 'usd',
|
||||||
|
tax: false,
|
||||||
|
taxValue: 0,
|
||||||
|
vat: false,
|
||||||
|
vatValue: 0,
|
||||||
|
first: '',
|
||||||
|
last: '',
|
||||||
|
email: '',
|
||||||
|
street: '',
|
||||||
|
city: '',
|
||||||
|
state: '',
|
||||||
|
postal: '',
|
||||||
|
phone: '',
|
||||||
|
paid: false,
|
||||||
|
website: '',
|
||||||
|
country: '',
|
||||||
|
zats: false,
|
||||||
|
invoices: false,
|
||||||
|
expiration: new Date(Date.now()).toISOString(),
|
||||||
|
payconf: false,
|
||||||
|
viewkey: ''
|
||||||
|
};
|
||||||
|
private invData_raw : string = '';
|
||||||
|
private invData_buff : any = null;
|
||||||
|
|
||||||
|
public reportType = 0;
|
||||||
|
public Status = 0;
|
||||||
|
|
||||||
|
constructor(private activatedRoute : ActivatedRoute,
|
||||||
|
private http : HttpClient ) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
var auth = 'Basic ' + Buffer.from(ConfigData.UsrPwd).toString('base64');
|
||||||
|
this.reqHeaders = new HttpHeaders().set('Authorization', auth);
|
||||||
this.activatedRoute.queryParams.subscribe((params) => {
|
this.activatedRoute.queryParams.subscribe((params) => {
|
||||||
this.pmtData.ownerId = params["ownerid"];
|
this.pmtData.ownerId = params["ownerid"];
|
||||||
this.pmtData.invoice = params["invoice"];
|
this.pmtData.invoice = params["invoiceNo"];
|
||||||
this.pmtData.amount = params["amount"];
|
this.pmtData.amount = params["amount"];
|
||||||
this.pmtData.currency = params["currency"];
|
this.pmtData.currency = params["currency"];
|
||||||
this.pmtData.shortcode = params["shortcode"];
|
this.pmtData.shortcode = params["shortCode"];
|
||||||
|
|
||||||
console.log(this.pmtData);
|
console.log(this.pmtData);
|
||||||
|
|
||||||
|
this.getInvoiceData( this.pmtData );
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getInvoiceData( reqData : PmtData ) {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Verify owner id ( Status = 1 if not exists )
|
||||||
|
// ( Status = 2 if service not available for user )
|
||||||
|
//
|
||||||
|
console.log('getOwner -> ', reqData.ownerId);
|
||||||
|
const ownParams = new HttpParams().append('id', reqData.ownerId);
|
||||||
|
let obs = this.http.get<{message:string, owner: any}>
|
||||||
|
( this.beUrl+'api/ownerid',
|
||||||
|
{ headers: this.reqHeaders,
|
||||||
|
params: ownParams,
|
||||||
|
observe: 'response'});
|
||||||
|
obs.subscribe((OwnerDataResponse) => {
|
||||||
|
//console.log('api/getowner', OwnerDataResponse.status);
|
||||||
|
if (OwnerDataResponse.status == 200) {
|
||||||
|
this.owner = OwnerDataResponse.body!.owner;
|
||||||
|
console.log('Owner => ' + this.owner.name );
|
||||||
|
if ( this.owner.payconf == false ) {
|
||||||
|
// process data
|
||||||
|
console.log("Owner check passed!!!");
|
||||||
|
this.getXeroInvoiceData( reqData );
|
||||||
|
} else {
|
||||||
|
console.log("Owner check failed!!!")
|
||||||
|
this.reportType = 2;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if ( OwnerDataResponse.status == 204 ) {
|
||||||
|
console.log('Res.Status = ' + OwnerDataResponse.status)
|
||||||
|
console.log('Owner id not found!!!');
|
||||||
|
this.reportType = 1;
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getXeroInvoiceData( reqData : PmtData ) {
|
||||||
|
|
||||||
|
// Call Xero API
|
||||||
|
let url : string = "http://localhost:3000/xero/" + reqData.invoice;
|
||||||
|
this.http
|
||||||
|
.get<any>(url)
|
||||||
|
.subscribe( data => {
|
||||||
|
console.log('Data >>> ' + data);
|
||||||
|
this.invData_raw = data.message.replaceAll("'",'"');
|
||||||
|
this.invData_buff = JSON.parse(this.invData_raw);
|
||||||
|
console.log('Invoice : >> ' + this.invData_raw);
|
||||||
|
this.invData.inv_Type = this.invData_buff.type;
|
||||||
|
this.invData.inv_Id = this.invData_buff.invoiceID;
|
||||||
|
this.invData.inv_No = this.invData_buff.invoiceNumber;
|
||||||
|
this.invData.inv_Contact = this.invData_buff.contact.name;
|
||||||
|
this.invData.inv_Currency = this.invData_buff.currencyCode;
|
||||||
|
this.invData.inv_CurrencyRate = this.invData_buff.currencyRate;
|
||||||
|
this.invData.inv_Total = this.invData_buff.total;
|
||||||
|
this.invData.inv_Status = this.invData_buff.status;
|
||||||
|
this.invData.inv_Date = new Date(this.invData_buff.date);
|
||||||
|
this.invData.inv_shortCode = reqData.shortcode;
|
||||||
|
// invoice number found, test if it's type is correct
|
||||||
|
if ( this.invData.inv_Type == 'ACCREC' ) {
|
||||||
|
console.log('Invoice type is correct!!');
|
||||||
|
// Test if invoice is not already paid
|
||||||
|
if ( this.invData.inv_Status == 'AUTHORISED') {
|
||||||
|
console.log('invoice is payable');
|
||||||
|
// Test if Invoice's currency is supported
|
||||||
|
if ( this.invData.inv_Currency == reqData.currency ) {
|
||||||
|
console.log('Invoice currency supported');
|
||||||
|
// Test if requested amount is as reported by Xero
|
||||||
|
if ( this.invData.inv_Total == reqData.amount ) {
|
||||||
|
console.log('Invoice amount Ok - create Order');
|
||||||
|
//
|
||||||
|
// =====> Create order here
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
console.log('Invoice amount does not match')
|
||||||
|
this.reportType = 8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Invoice currency not supported');
|
||||||
|
this.reportType = 7;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Invoice already paid');
|
||||||
|
this.reportType = 6;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Invoice type is invalid' );
|
||||||
|
this.reportType = 5;
|
||||||
|
}
|
||||||
|
// Save invData in database
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
if ( error.status == 404 ) {
|
||||||
|
this.reportType = 4;
|
||||||
|
console.log('Invoice not found (' + JSON.stringify(error) +')' );
|
||||||
|
} else {
|
||||||
|
this.reportType = 3;
|
||||||
|
console.log('Xero server inaccesible! (' + JSON.stringify(error) + ')');
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
console.log("Request complete")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
http://localhost:4200/pmtservice?ownerid=Rene&amount=30¤cy=USD&invoice=INV-003234&shortcode=abcde
|
http://localhost:4200/pmtservice?ownerid=62cca13f5530331e2a97c78e&invoiceNo=INV-0034¤cy=USD&amount=753.95&shortCode=!w8T62
|
13
src/app/pmtservice/xeroinvoice.model.ts
Normal file
13
src/app/pmtservice/xeroinvoice.model.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export interface XeroInvoice {
|
||||||
|
inv_Type : String;
|
||||||
|
inv_Id : String;
|
||||||
|
inv_No : String;
|
||||||
|
inv_Contact : String;
|
||||||
|
inv_Currency : String;
|
||||||
|
inv_CurrencyRate : number;
|
||||||
|
inv_Total : number;
|
||||||
|
inv_Status : String;
|
||||||
|
inv_Date : Date;
|
||||||
|
inv_shortCode : String;
|
||||||
|
inv_ProcDate : Date;
|
||||||
|
}
|
|
@ -72,6 +72,9 @@ export class ViewerComponent implements OnInit {
|
||||||
this.ownerUpdate.subscribe((owner) => {
|
this.ownerUpdate.subscribe((owner) => {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// console.log(this.owner._id);
|
||||||
|
|
||||||
this.userUpdate = userService.userUpdate;
|
this.userUpdate = userService.userUpdate;
|
||||||
this.userUpdate.subscribe((user) => {
|
this.userUpdate.subscribe((user) => {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
Loading…
Reference in a new issue