Basic IIF rendering with test component for BOD-83
This commit is contained in:
@@ -1,143 +1,49 @@
|
||||
import { Editor } from "@tinymce/tinymce-react";
|
||||
import axios from "axios";
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { EmailSettings } from "../../utils/TemplateConstants";
|
||||
import {
|
||||
endLoading,
|
||||
startLoading,
|
||||
} from "../../redux/application/application.actions";
|
||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
||||
load: () => dispatch(startLoading()),
|
||||
endload: () => dispatch(endLoading()),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function Test({ setEmailOptions, load, endload, bodyshop }) {
|
||||
const [state, setState] = useState(temp);
|
||||
|
||||
const handleEditorChange = (content, editor) => {
|
||||
setState(content);
|
||||
)(function Test({ bodyshop }) {
|
||||
const handle = async () => {
|
||||
console.log(
|
||||
"await auth.currentUser.getIdToken(true)",
|
||||
await auth.currentUser.getIdToken(true)
|
||||
);
|
||||
const response = await axios.post(
|
||||
"/accounting/iif/receivables",
|
||||
{ jobId: "661dd1d5-bf06-426f-8bd2-bd9e41de8eb1" },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("handle -> result", response);
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.setAttribute(
|
||||
"download",
|
||||
response.headers.filename || "receivables.iif"
|
||||
); //or any other extension
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
axios
|
||||
.post("/render", {
|
||||
view: state,
|
||||
context: {
|
||||
people: ["Yehuda Katz", "Alan Johnson", "Charles Jolley"],
|
||||
},
|
||||
})
|
||||
.then((r) => {
|
||||
var newWin = window.open(
|
||||
"url",
|
||||
"windowName",
|
||||
"height=300,width=300"
|
||||
);
|
||||
newWin.document.write(r.data);
|
||||
});
|
||||
}}>
|
||||
TinyMCE
|
||||
</button>
|
||||
<Editor
|
||||
value={state}
|
||||
apiKey='f3s2mjsd77ya5qvqkee9vgh612cm6h41e85efqakn2d0kknk'
|
||||
init={{
|
||||
height: 500,
|
||||
//menubar: false,
|
||||
encoding: "raw",
|
||||
extended_valid_elements: "span",
|
||||
|
||||
plugins: [
|
||||
"advlist autolink lists link image charmap print preview anchor",
|
||||
"searchreplace visualblocks code fullscreen",
|
||||
"insertdatetime media table paste code help wordcount",
|
||||
],
|
||||
toolbar:
|
||||
"undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help",
|
||||
}}
|
||||
onEditorChange={handleEditorChange}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={() =>
|
||||
setEmailOptions({
|
||||
messageOptions: {
|
||||
to: "patrickwf@gmail.com",
|
||||
Subject: "TODO FIX ME",
|
||||
},
|
||||
template: {
|
||||
name: "appointment_reminder",
|
||||
variables: { id: "2b42336f-b8de-4f04-a053-d6bff034d384" },
|
||||
},
|
||||
})
|
||||
}>
|
||||
Set email config.
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
setEmailOptions({
|
||||
messageOptions: {
|
||||
from: {
|
||||
name: bodyshop.shopname || EmailSettings.fromNameDefault,
|
||||
address: EmailSettings.fromAddress,
|
||||
},
|
||||
to: "patrickwf@gmail.com",
|
||||
replyTo: bodyshop.email,
|
||||
Subject: "TODO FIX ME",
|
||||
},
|
||||
template: {
|
||||
name: "parts_order_confirmation",
|
||||
variables: { id: "6fea31e9-ea85-4c89-ac56-6f9cc84531fe" },
|
||||
},
|
||||
})
|
||||
}>
|
||||
Parts Order
|
||||
</button>
|
||||
<button onClick={handle}>Hit with Header.</button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const temp = `<div style="font-family: Arial, Helvetica, sans-serif;">
|
||||
<p style="text-align: center;"><span>→<span> This is a full-featured editor demo. </span>Please explore! ←</span></p>
|
||||
<p style="text-align: center;"> </p>
|
||||
<h2 style="text-align: center;"><span>TinyMCE is the world's most customizable, and flexible, rich text editor.</span></h2>
|
||||
<p style="text-align: center;"><span><strong> A featherweight download, TinyMCE can handle any challenge you throw at it. </strong></span></p>
|
||||
<p style="text-align: center;"> </p>
|
||||
<p> </p>
|
||||
<table style="border-collapse: collapse; width: 85%; height: 86px; border-color: initial; border-style: solid; margin-left: auto; margin-right: auto;">
|
||||
<tbody>
|
||||
<tr style="height: 22px;">
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px;"><span>🛠 50+ Plugins</span></td>
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px;"><span>💡 Premium Support</span></td>
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px;"><span>🖍 Custom Skins</span></td>
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px;"><span>⚙ Full API Access</span></td>
|
||||
</tr>
|
||||
<tr style="height: 21px; display: none;">
|
||||
<td style="height: 21px; display: none;"><span>{{#each people}}</span></td>
|
||||
</tr>
|
||||
<tr style="height: 22px;">
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px; border-style: solid; border-width: 1px;"><span>{{this}}</span></td>
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px; border-style: solid; border-width: 1px;"><span>{{this}}</span></td>
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px; border-style: solid; border-width: 1px;"><span>{{this}}</span></td>
|
||||
<td style="width: 25%; text-align: center; padding: 7px; height: 22px; border-style: solid; border-width: 1px;"><span>{{this}}</span></td>
|
||||
</tr>
|
||||
<tr style="height: 21px; display: none;">
|
||||
<td style="height: 21px;"><span>{{/each}}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>`;
|
||||
|
||||
@@ -50,7 +50,7 @@ export function JobsCloseSaveButton({
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
console.log("suspense", suspenseAmount);
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
|
||||
@@ -576,7 +576,7 @@
|
||||
"rate_la3": "LA3 Rate",
|
||||
"rate_la4": "LA4 Rate",
|
||||
"rate_laa": "Aluminum Rate",
|
||||
"rate_lab": "Labor Rate",
|
||||
"rate_lab": "Body Rate",
|
||||
"rate_lad": "Diagnostic Rate",
|
||||
"rate_lae": "Electrical Rate",
|
||||
"rate_laf": "Frame Rate",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"cloudinary": "^1.21.0",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "2.8.5",
|
||||
"dinero.js": "^1.8.1",
|
||||
"dotenv": "8.2.0",
|
||||
"express": "^4.16.4",
|
||||
"express-sslify": "^1.2.0",
|
||||
|
||||
12
server.js
12
server.js
@@ -31,10 +31,18 @@ var sendEmail = require("./sendemail.js");
|
||||
app.post("/sendemail", sendEmail.sendEmail);
|
||||
|
||||
//Test route to ensure Express is responding.
|
||||
app.get("/test", function (req, res) {
|
||||
res.status(200).send();
|
||||
app.get("/test", async function (req, res) {
|
||||
res.status(200).send("OK");
|
||||
});
|
||||
|
||||
app.post("/test", async function (req, res) {
|
||||
res.status(200).send("OK");
|
||||
});
|
||||
|
||||
//Invoicing-IIF
|
||||
const accountingIIF = require("./server/accounting/iif/iif");
|
||||
app.post("/accounting/iif/receivables", accountingIIF.receivables);
|
||||
|
||||
//Cloudinary Media Paths
|
||||
var media = require("./server/media/media");
|
||||
app.post("/media/sign", media.createSignedUploadURL);
|
||||
|
||||
58
server/accounting/iif/iif-receivables.js
Normal file
58
server/accounting/iif/iif-receivables.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
const queries = require("../../graphql-client/queries");
|
||||
|
||||
exports.default = async (req, res) => {
|
||||
const BearerToken = req.headers.authorization;
|
||||
const { jobId } = req.body;
|
||||
|
||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||
headers: {
|
||||
Authorization: BearerToken,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await client
|
||||
.setHeaders({ Authorization: BearerToken })
|
||||
.request(queries.QUERY_JOBS_FOR_RECEIVABLES_EXPORT, { id: jobId });
|
||||
|
||||
const response = [];
|
||||
response.push(TRNS_HEADER);
|
||||
response.push(generateInvoiceHeader(result.jobs_by_pk));
|
||||
response.push(END_TRNS);
|
||||
|
||||
res.setHeader("Content-type", "application/octet-stream");
|
||||
res.setHeader("Content-disposition", "attachment; filename=file.txt");
|
||||
res.setHeader("filename", `${result.jobs_by_pk.ro_number}-RECEIVABLES.iif`);
|
||||
res.send(response.join("\n"));
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
};
|
||||
|
||||
const TRNS_HEADER = `!TRNS TRNSID TRNSTYPE DATE ACCNT NAME CLASS AMOUNT DOCNUM MEMO CLEAR TOPRINT NAMEISTAXABLE ADDR1 ADDR2 ADDR3 ADDR4 DUEDATE TERMS OTHER1 PONUM
|
||||
!SPL SPLID TRNSTYPE DATE ACCNT NAME CLASS AMOUNT DOCNUM MEMO CLEAR QNTY PRICE INVITEM PAYMETH TAXABLE VALADJ SERVICEDATE OTHER2 EXTRA
|
||||
!ENDTRNS`;
|
||||
|
||||
const generateInvoiceHeader = (job) =>
|
||||
`TRNS INVOICE ${new Date(job.date_invoiced).getMonth() + 1}/${new Date(
|
||||
job.date_invoiced
|
||||
).getDate()}/${new Date(
|
||||
job.date_invoiced
|
||||
).getFullYear()} Accounts Receivable GUO DA Acct.# ${job.ownr_id}:${
|
||||
job.ro_number
|
||||
} 0100 ${job.clm_total} ${job.ro_number} N N Y GUO DA Acct.# ${job.ownr_id}:${
|
||||
job.ro_number
|
||||
} ${job.ownr_addr1} ${job.ownr_city} ${job.ownr_st} ${job.ownr_zip} `;
|
||||
const generateInvoiceLine = (line) =>
|
||||
`SPL INVOICE 05/21/2020 Sales:Total Labour:Sales, Body Shop Labour 0100 -572.60 114519 Labor Body N 572.60 Total Labour:4015 Y N `;
|
||||
|
||||
const END_TRNS = `ENDTRNS`;
|
||||
1
server/accounting/iif/iif.js
Normal file
1
server/accounting/iif/iif.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.receivables = require("./iif-receivables").default
|
||||
@@ -1,10 +1,17 @@
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const path = require("path");
|
||||
require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || 'development'}`) });
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
|
||||
//TODO May need to use a different client that includes caching of resources.
|
||||
//TODO May need to use a different client that includes caching of resources.
|
||||
exports.client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||
headers: {
|
||||
"x-hasura-admin-secret": process.env.HASURA_ADMIN_SECRET
|
||||
}
|
||||
"x-hasura-admin-secret": process.env.HASURA_ADMIN_SECRET,
|
||||
},
|
||||
});
|
||||
|
||||
exports.unauthclient = new GraphQLClient(process.env.GRAPHQL_ENDPOINT);
|
||||
|
||||
@@ -39,3 +39,27 @@ mutation UPDATE_MESSAGE($msid: String!, $fields: messages_set_input!) {
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
exports.QUERY_JOBS_FOR_RECEIVABLES_EXPORT = `
|
||||
query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($id: uuid!){
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
job_totals
|
||||
date_invoiced
|
||||
ro_number
|
||||
clm_total
|
||||
invoice_allocation
|
||||
ownerid
|
||||
ownr_addr1
|
||||
ownr_addr2
|
||||
ownr_zip
|
||||
ownr_city
|
||||
ownr_st
|
||||
|
||||
}
|
||||
bodyshops{
|
||||
id
|
||||
md_responsibility_centers
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -803,6 +803,11 @@ dicer@^0.3.0:
|
||||
dependencies:
|
||||
streamsearch "0.1.2"
|
||||
|
||||
dinero.js@^1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/dinero.js/-/dinero.js-1.8.1.tgz#775a647629b4195af9d02f46e9b7fa1fd81e906d"
|
||||
integrity sha512-AQ09MDKonkGUrhBZZFx4tPTVcVJuHJ0VEA73LvcBoBB2eQSi1DbapeXj4wnUUpx1hVnPdyev1xPNnNMGy/Au0g==
|
||||
|
||||
doctrine@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
|
||||
|
||||
Reference in New Issue
Block a user