@elitedcs/ghl-mcp 3.65.1 → 3.65.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.65.2 — invoicing never worked, and the guide stopped being one long page
4
+
5
+ - **Fix: creating an invoice failed every single time.** The call sent five
6
+ fields; GoHighLevel needs eleven, and it names line-item amounts differently
7
+ than we did. Given a payload it could not read, their server crashed rather
8
+ than telling us what was missing, so this looked like an outage on their side
9
+ rather than a bug on ours. It has never worked for anyone. Invoices now carry
10
+ the currency, the dates, your business name and the client's own details, and
11
+ are created as real payable drafts unless you ask for a test one.
12
+
13
+ **The user guide is a library again, not a scroll.**
14
+
15
+ - **Cards open their own page.** The guide had drifted into a single document
16
+ that printed the index and then every guide beneath it, growing by one whole
17
+ guide each release. Opening a card now shows that guide on its own, from the
18
+ top, and the back button works.
19
+ - **The category menu is back**, above the cards.
20
+ - **It stays light.** The guide used to follow your computer into dark mode,
21
+ which is wrong for something people read at length, print, and save as a PDF.
22
+ - **It prints properly now.** One guide per job, no navigation, no buttons, no
23
+ index bleeding into the page.
24
+ - Fixed a layout bug that had been chopping numbered steps into narrow columns
25
+ whenever a step contained a command. The install guide's first step was the
26
+ worst hit, which is the first thing a new customer reads.
27
+
28
+ **Three new guides, each proven live before shipping:**
29
+
30
+ - **What your AI bot knows, and where to put it.** Custom values resolve in a
31
+ bot's prompt and are silently ignored in its knowledge base. Asked a question
32
+ whose answer sat behind an unresolved token, a test bot named a nearby
33
+ sentence as the person responsible. Worse, if the same fact also sits in the
34
+ prompt the bot quietly repairs the answer, so the bug passes exactly the test
35
+ you would run.
36
+ - **Bill a client and see what you were paid.** Invoices, products, coupons, and
37
+ the difference between money invoiced and money received.
38
+ - **Reuse a build across client accounts.** Snapshots, and the honest list of
39
+ what does not travel with one.
40
+
3
41
  ## 3.65.1 — the guide caught up with the product
4
42
 
5
43
  No code changes. The built-in user guide ships inside the install, so it goes
package/dist/index.js CHANGED
@@ -2854,7 +2854,7 @@ var require_package = __commonJS({
2854
2854
  "package.json"(exports2, module2) {
2855
2855
  module2.exports = {
2856
2856
  name: "@elitedcs/ghl-mcp",
2857
- version: "3.65.1",
2857
+ version: "3.65.2",
2858
2858
  mcpName: "io.github.drjerryrelth/ghl-command",
2859
2859
  description: "GoHighLevel MCP Server for Claude. 238 tools \u2014 full CRM, automation, marketing control, account-wide workflow audit, live funnel-capture verification, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
2860
2860
  main: "dist/index.js",
@@ -8648,6 +8648,38 @@ function registerProductTools(server2, client) {
8648
8648
 
8649
8649
  // src/tools/invoices.ts
8650
8650
  var import_zod20 = require("zod");
8651
+ function buildCreateInvoiceBody(args, resolvedLocationId, contact, businessName, today) {
8652
+ const currency = args.currency ?? args.items[0]?.currency ?? "USD";
8653
+ return {
8654
+ altId: resolvedLocationId,
8655
+ altType: "location",
8656
+ name: args.name,
8657
+ title: args.title ?? args.name,
8658
+ currency,
8659
+ // GHL's line items are `amount` and `qty`. Sending price/quantity leaves
8660
+ // both undefined on their side, which is the crash.
8661
+ items: args.items.map((i) => ({
8662
+ name: i.name,
8663
+ description: i.description ?? "",
8664
+ currency: i.currency ?? currency,
8665
+ amount: i.price,
8666
+ qty: i.quantity
8667
+ })),
8668
+ discount: args.discount ?? { type: "percentage", value: 0 },
8669
+ termsNotes: args.termsNotes ?? "",
8670
+ businessDetails: { name: businessName },
8671
+ contactDetails: {
8672
+ id: contact.id,
8673
+ name: contact.name ?? "",
8674
+ email: contact.email ?? "",
8675
+ phoneNo: contact.phone ?? ""
8676
+ },
8677
+ issueDate: args.issueDate ?? today,
8678
+ dueDate: args.dueDate ?? args.issueDate ?? today,
8679
+ // Real, payable invoice unless the caller explicitly asks for a test one.
8680
+ liveMode: args.liveMode ?? true
8681
+ };
8682
+ }
8651
8683
  function registerInvoiceTools(server2, client) {
8652
8684
  safeTool(
8653
8685
  server2,
@@ -8713,30 +8745,47 @@ function registerInvoiceTools(server2, client) {
8713
8745
  contactId: import_zod20.z.string().describe("Contact ID for the invoice"),
8714
8746
  items: import_zod20.z.array(import_zod20.z.object({
8715
8747
  name: import_zod20.z.string().describe("Item name"),
8716
- description: import_zod20.z.string().describe("Item description"),
8748
+ description: import_zod20.z.string().optional().describe("Item description"),
8717
8749
  quantity: import_zod20.z.number().describe("Item quantity"),
8718
- price: import_zod20.z.number().describe("Item price"),
8719
- currency: import_zod20.z.string().describe("Currency code (e.g. USD)")
8720
- })).describe("Invoice line items"),
8750
+ price: import_zod20.z.number().describe("Unit price, in the invoice currency."),
8751
+ currency: import_zod20.z.string().optional().describe("Currency code (e.g. USD). Defaults to the invoice currency.")
8752
+ })).min(1).describe("Invoice line items"),
8753
+ currency: import_zod20.z.string().optional().describe("Invoice currency code, e.g. 'USD'. Defaults to the first item's currency, then USD."),
8721
8754
  discount: import_zod20.z.object({
8722
8755
  type: import_zod20.z.string().optional().describe("Discount type: 'percentage' or 'fixed'."),
8723
8756
  value: import_zod20.z.number().optional().describe("Discount amount: percent (0-100) when type=percentage, currency amount when type=fixed.")
8724
8757
  }).optional().describe("Discount to apply"),
8725
8758
  termsNotes: import_zod20.z.string().optional().describe("Terms and notes for the invoice"),
8726
- title: import_zod20.z.string().optional().describe("Invoice title")
8759
+ title: import_zod20.z.string().optional().describe("Invoice title. Defaults to the invoice name."),
8760
+ issueDate: import_zod20.z.string().optional().describe("Issue date, YYYY-MM-DD. Defaults to today."),
8761
+ dueDate: import_zod20.z.string().optional().describe("Due date, YYYY-MM-DD. Defaults to the issue date."),
8762
+ liveMode: import_zod20.z.boolean().optional().describe("true (default) creates a real, payable invoice. false creates a test-mode invoice that cannot be paid.")
8727
8763
  },
8728
- async ({ locationId: locationId2, name, contactId, items, discount, termsNotes, title }) => {
8764
+ async ({ locationId: locationId2, name, contactId, items, currency, discount, termsNotes, title, issueDate, dueDate, liveMode }) => {
8729
8765
  const resolvedLocationId = client.resolveLocationId(locationId2);
8730
- const body = {
8731
- altId: resolvedLocationId,
8732
- altType: "location",
8733
- name,
8734
- contactId,
8735
- items
8766
+ const contactRes = await client.get(`/contacts/${contactId}`);
8767
+ const c = contactRes?.contact ?? contactRes ?? {};
8768
+ const contact = {
8769
+ id: contactId,
8770
+ name: [c.firstName, c.lastName].filter(Boolean).join(" ") || c.name || "",
8771
+ email: c.email ?? "",
8772
+ phone: c.phone ?? ""
8736
8773
  };
8737
- if (discount !== void 0) body.discount = discount;
8738
- if (termsNotes !== void 0) body.termsNotes = termsNotes;
8739
- if (title !== void 0) body.title = title;
8774
+ let businessName = "";
8775
+ try {
8776
+ const loc = await client.get(`/locations/${resolvedLocationId}`);
8777
+ const l = loc?.location ?? loc ?? {};
8778
+ businessName = l.name ?? "";
8779
+ } catch {
8780
+ }
8781
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8782
+ const body = buildCreateInvoiceBody(
8783
+ { name, contactId, items, currency, discount, termsNotes, title, issueDate, dueDate, liveMode },
8784
+ resolvedLocationId,
8785
+ contact,
8786
+ businessName,
8787
+ today
8788
+ );
8740
8789
  return client.post("/invoices/", { body });
8741
8790
  }
8742
8791
  );