jksn.ie
Work Contact
Jamie Jackson
Jamie Jackson NetSuite consultant & developer · Ireland

Your NetSuite.
Your Way.

Custom modules, integrations and mobile tools, built inside your account rather than bolted on beside it.

Products

{{ count }}
All work
01 / Integration

Email-to-ERP sales order automation

A wholesale distributor was receiving several hundred purchase orders a day as email attachments, and keying every one of them into NetSuite by hand.

{{ m.k }}
{{ m.v }}

Problem

01

Orders arrived in a shared mailbox in a dozen different layouts: supplier PDFs, spreadsheet attachments, and plain text in the body of the mail. Two people spent most of their morning transcribing them, which meant orders received after 11am were rarely entered the same day.

The cost wasn't only the hours. Transcription errors surfaced downstream as short shipments and credit notes, and nobody could say with confidence how long an order had been sitting unprocessed.

  • · {{ p }}

Approach

02

Rather than chase a parser that could handle every layout, we split the problem in two: an extraction service that gets a structured order out of the message, and a NetSuite-side integration that only ever accepts clean, validated payloads.

Anything the extractor is unsure about, whether an unknown item code, a price that doesn't match the contract or a customer it can't identify, is routed to an exception queue with the original email attached, so a human resolves it in context instead of re-keying it.

Fig. 01 / Order intake pipeline 01 → 05, in sequence
{{ n.step }} {{ n.name }} {{ n.detail }}
05 Sales Order Approved, linked to source email
Fallback Exception queue Unmatched item, price variance or unknown customer → resolved in NetSuite with original email attached

Outcome

03

Orders now post within minutes of arriving, including overnight. The two people who were transcribing them spend their morning on the exception queue instead, which on a normal day is a handful of items.

{{ o.stat }} {{ o.label }}
All work
Standalone 01 / Product

MyKit: multi-tenant teamwear commerce platform

A white-label SaaS platform that lets sportswear suppliers run branded online club shops, design custom kits, take payments, manage stock, and sync orders to their ERP, all from a single dashboard.

mykit.ie
{{ m.k }}
{{ m.v }}

Overview

01

MyKit is a production multi-tenant commerce platform built for the sports teamwear industry. Sportswear suppliers sign up as organisations, then spin up individual, time-limited online shops for each club they supply: a GAA club, a rugby team, a school. Parents and players order personalised kit (name, number, size) through the club's own branded storefront; the supplier manages every order, payment, stock movement and fulfilment step from one admin console.

The problem it solves: teamwear suppliers traditionally take orders via spreadsheets, WhatsApp groups and paper forms, then manually collate hundreds of personalised items per club. MyKit replaces that with a structured, self-service pipeline from shop launch to shipped parcel.

Fig. 01 / Three portals, one pipeline org-scoped, per request
{{ p.step }} {{ p.name }} {{ p.detail }}
Also Point of Sale Same inventory and order pipeline as online
Out Odoo ERP Bi-directional RPC sync with retry log

Key features

02
{{ featCount }}
{{ f.n }}

{{ f.name }}

{{ f.body }}

  • · {{ li }}
{{ s.n }} {{ s.name }}
Fig. 02 / Admin dashboard supplier console, org home
kilbridesportswear.mykit.ie/admin
MyKit
{{ t }}
KS Kilbride Sportswear kilbridesportswear.mykit.ie
Quick actions
{{ a.g }}{{ a.t }}
{{ s.k }} {{ s.v }} {{ s.sub }}

Admin Dashboard

Welcome back, Jamie Jackson
Company details View
{{ r.k }} {{ r.v }}
Recent sales View all →
OrderShopCustomerStatusAmount
{{ o.id }}{{ o.date }} {{ o.shop }} {{ o.who }} Paid {{ o.amt }}
Clubs Manage your sports clubs and their shops Add
Club nameActiveShopOpen dateClose dateProductsKitsOrdersRevenue
{{ c.badge }} {{ c.name }} {{ c.slug }} Yes {{ c.status }} {{ c.open }} {{ c.close }} {{ c.products }} {{ c.kits }} {{ c.orders }} {{ c.rev }}
Kilbride LoginCart (0)
Kilbride / Ardclough GAA
AG Ardclough GAA Shop Please note: this shop is a pre-order portal, orders may take 5/6 weeks for delivery from the close date of the club shop.
Ardclough GAA Shop live now Opens: 13 Feb 2026, 10:00 Closes: 3 Mar 2026, 23:59 Closes in: {{ t.v }} {{ t.k }}
Products
{{ p.name }} {{ p.price }} Add to cart
Kilbride LoginCart
AG Ardclough GAA Shop Pre-order portal. Orders ship 5/6 weeks after the shop closes.
Shop live now Closes: 3 Mar 2026, 23:59 {{ t.v }} {{ t.k }}
Products
{{ p.name }} {{ p.price }} Add to cart
ardclough-gaa.mykit.ie/kit-builder

Kit Builder

Design your custom sportswear in six steps
{{ s.i }} {{ s.name }}
Customise colours
Click a colour swatch to apply it to each zone.
Custom jersey preview
{{ z.name }}
Back Continue to logos
kilbridesportswear.mykit.ie/admin/pos
MyKit
{{ t.name }}

Point of Sale

All clubs Search products… Show closed
{{ g.club }}
{{ p.name }} {{ p.price }} {{ p.stock }}
Cart (3 items)
{{ c.name }} × {{ c.club }} Size: {{ c.size }} 1 + {{ c.price }}
Subtotal (ex VAT)€130.00 VAT (23%)€19.78 Total€149.78 Proceed to checkout
kilbridesportswear.mykit.ie/admin/expenses
MyKit
{{ t.name }}
Expenses 4 receipts · €381.37 tracked Reports Categories Scan receipt
Edit receipt Extracted by Claude. Check the details below. 9 fields, 8 line items
{{ f.k }} {{ f.v }}
Category Manage Materials & supplies
{{ f.k }} {{ f.v }}
{{ f.k }} {{ f.v }}
Line items + Add line item
{{ l.name }} {{ l.amt }}
Mark as submitted Delete Cancel Save receipt
kilbridesportswear.mykit.ie/admin/inventory
MyKit
{{ t.name }}
KS Kilbride Sportswear kilbridesportswear.mykit.ie
Quick actions
{{ a.g }}{{ a.t }}
{{ s.k }} {{ s.v }}

Inventory

Real-time stock monitoring and management
Search Search by name or SKU… Filter by club All clubs Auto-refresh 10 seconds Refresh now
Previous Page 1 of 40 (799 total) Next
ProductClubPriceTotalReservedAvailableStatusActions
{{ r.name }} ID: {{ r.id }} {{ r.club }} {{ r.price }} {{ r.total }} {{ r.reserved }} {{ r.available }} In stock −1 +10
kilbridesportswear.mykit.ie/admin/setup/roles
MyKit
{{ t.name }}
Admin 49 permissions
Role details Permissions {{ p.name }} {{ p.count }}
← Back to roles

Edit role: Admin

System
System role. The name cannot be changed but permissions can be modified.
Orders View and manage customer orders 5/5 selected Deselect all
{{ r.name }} {{ r.desc }}
Cancel Save changes
kilbridesportswear.mykit.ie/ardclough-gaa/cart
Kilbride LoginCart (2)
Shopping cart 2 items in your cart
{{ c.name }} {{ c.price }} {{ c.club }} Size: {{ c.size }} Qty: 1 Remove
Order summary Discount code Enter code Apply Subtotal (ex VAT)€73.77 VAT (23%)€8.23 ShippingCalculated at checkout Total €82.00 Proceed to checkout Secure checkout powered by Stripe Continue shopping

Engineering

03
  • {{ e.name }}

    {{ e.body }}

Stack & scale

04
{{ o.stat }} {{ o.label }}
{{ t.k }}
{{ t.v }}
All work
05 / Mobile app

NetSuite Pulse: a modular mobile platform that lives inside NetSuite

A phone app deployed into any customer's NetSuite account, where they switch on only the add-ins they need and commission new ones for the workflows that are specific to them. The whole thing is one Suitelet: NetSuite serves the interface, holds the data and enforces the permissions.

{{ m.k }}
{{ m.v }}

Problem

01

Consultants and sales reps spend their week on client sites. Timesheets got written up on Friday from memory, receipts arrived in envelopes weeks late, and approvals waited for a manager to be at a desk. The standard NetSuite mobile experience covers none of the custom workflows the business actually runs on.

A native app would have meant a second identity system, a second permission model, an external server holding financial data, and an app store release for every change. None of that was proportionate to the problem — and none of it would survive being deployed into a second customer's account, where the workflows are different again.

  • · {{ p }}

Approach

02

One Suitelet does both jobs. A GET request returns the entire single-page app as an inline HTML string, with no CDN links and no framework. Every subsequent interaction is a POST carrying a JSON body with an action and a session token, and the same script routes it.

Permissions are data, not code. Each app role is a custom record holding a permission level per feature, and every one of the 51 routed actions declares the feature and minimum level it requires. Adding a feature means adding a row, not editing a script.

Reads use SuiteQL so that joins and aggregations cost one query instead of a loop of lookups; writes go through the record module. Every service function documents its governance cost in its module header.

That structure is what makes the app deployable rather than bespoke. Each feature is a self-contained page module with its own actions, records and permission entries, so an account gets only the add-ins it turns on and a custom add-in for one customer is a new module rather than a fork of the app.

Fig. 01 / Request path Every POST, in order
{{ n.step }} {{ n.name }} {{ n.detail }}
05 JSON envelope status · data · message
Rejected Expired token or insufficient level → error envelope, logged to login history with device, browser and IP

The app

03
14 page modules · 375–430px
NetSuite Pulse 3
Thursday, 6 August Good morning, Jamie Sales Rep
{{ t.k }} {{ t.v }} {{ t.sub }}
Needs you
{{ r.t }} {{ r.s }}
{{ b.g }} {{ b.t }}
Dashboard · one SuiteQL round trip
Ask NetSuite
Which customers haven't ordered since April?
Scope: team 4 tables allowed
Generated SuiteQL ✓ validated
SELECT c.entityid, c.companyname, MAX(t.trandate) AS last_order FROM customer c JOIN transaction t ON t.entity = c.id WHERE t.type = 'SalesOrd' GROUP BY c.entityid, c.companyname HAVING MAX(t.trandate) < '01/04/2026'
+ scope filter + FETCH FIRST 50 ROWS ONLY
9 rows
{{ r.n }} {{ r.d }}
Email results
Natural language → validated SuiteQL

Letting a model write SQL

04

The search feature sends a plain-English question to Claude along with a schema description, and runs the SuiteQL that comes back. That is only safe because the model is never trusted with the last word.

The schema it sees is assembled from the searchable tables the user's role is permitted, so the prompt itself cannot reference anything out of bounds. What comes back then passes four gates before it touches the database.

  • · {{ g }}

Every executed query is written to an audit log with the role that ran it and the SQL that ran. The same pattern drives receipt scanning: a photo goes to the vision model, and a structured expense line comes back for the user to confirm rather than accept.

Stack & scale

05
{{ o.stat }} {{ o.label }}
{{ t.k }}
{{ t.v }}
All work
03 / Internal tool

Slate: planning that writes itself into the timesheet

Project managers plan the week by dragging people onto tasks. The same plan is projected into real NetSuite time entries, so a consultant opens their timesheet to find it already filled in.

{{ m.k }}
{{ m.v }}

Problem

01

NetSuite holds the projects, the tasks, the budgets and the time. It does not hold the plan. Who is doing what next Tuesday lived in a spreadsheet beside it, maintained by hand and out of date within a day.

Because the plan and the ledger never met, the same information was entered twice: once when a manager scheduled the work, again when the consultant wrote up their timesheet at the end of the week from memory.

  • · {{ p }}

Approach

02

One Suitelet serves five views off a ?view= parameter. Each view owns its own model building and rendering; a shared page shell wraps the same chrome around whatever comes back, so a new view is a new module rather than a branch in a growing script.

Planning is the only thing the dashboard writes. Dragging a person onto a task and a day creates an allocation on a custom record, and that record is the single source the board, the resource view and the timesheet sync all read from — packed the same way by one shared module, so the three can never disagree.

Everything else is read: SuiteQL for joins and aggregations, and N/search only for the handful of fields SuiteQL cannot reach. Hours land against a person's real working calendar, so leave and non-working days push work forward instead of absorbing it.

Fig. 01 / Five views, one script ?view=
{{ v.q }} {{ v.name }} {{ v.detail }}
app.netsuite.com/…/sl_pm_dashboard.js?view=plan&pm=10202
JKSN Slate Schedule
AllIrelandUnited Kingdom
Project Manager Jamie Jackson
Home ProjectsProjects ResourcesTimesheetsScheduleResource Allocation
Team · drag a person onto a task & day
CDCiara D.MOMarek O.RBRónán B.AKAoife K.
Project · task
Mon 3Tue 4Wed 5Thu 6Fri 7Mon 10Tue 11Wed 12Thu 13Fri 14
Data migration — dry runCoyle Group · 64h planned
Ciara D. · 21hMarek O. · 14h
UAT supportDoran Foods · 40h planned
Rónán B. · 21hAoife K.
Go-live cutoverCoyle Group · 24h planned
Ciara D. · 14h
Document templates — buildRialto Print · 32h planned
Marek O. · 14hAoife K. · 14h
Fig. 02 / Schedule board — grey columns are days the person cannot work

Writing into someone else's timesheet

03

A plan that generates time entries is a plan that can quietly corrupt payroll and billing. The sync is therefore written to be reversible and unfailing: it never throws, and every rule below exists to protect something a person did by hand.

  • · {{ s }}

Writes are gated on the way in as well. The deployment runs as administrator, so before anything is saved the acting user must be an administrator or a listed project manager, and the employee being scheduled must report to that manager. Every write is logged with the user who made it.

Stack & shape

04
{{ o.stat }} {{ o.label }}
{{ t.k }}
{{ t.v }}