{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "SpoolMargin job v2",
  "type": "object",
  "required": [
    "product",
    "version",
    "name",
    "actualsEnabled",
    "fields"
  ],
  "properties": {
    "product": {
      "const": "3d-print-job-costing"
    },
    "version": {
      "const": 2
    },
    "name": {
      "type": "string",
      "maxLength": 100
    },
    "actualsEnabled": {
      "type": "boolean"
    },
    "demo": {
      "type": "boolean"
    },
    "fields": {
      "type": "object",
      "required": [
        "quantity",
        "grams",
        "material",
        "hours",
        "watts",
        "energy",
        "machine",
        "salvage",
        "lifeHours",
        "maintenance",
        "laborRate",
        "setup",
        "post",
        "failure",
        "packaging",
        "shipping",
        "overhead",
        "margin",
        "quote",
        "feePercent",
        "feeFixed"
      ],
      "properties": {
        "quantity": {
          "type": "integer",
          "minimum": 1,
          "maximum": 10000,
          "description": "Finished parts. parts / order. Number of identical successful parts to deliver."
        },
        "grams": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Material per part. g / attempt. Include supports, brim, purge, and other consumed filament."
        },
        "material": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Filament price. $ / kg. Use the price you actually pay, including delivery."
        },
        "hours": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Print time per part. hours / attempt. For a multi-part plate, divide total time by its part count."
        },
        "watts": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Average power draw. watts. Measured average while printing, not the power supply rating."
        },
        "energy": {
          "type": "number",
          "minimum": 0,
          "maximum": 20,
          "description": "Electricity rate. $ / kWh. Use the applicable rate from your electricity bill."
        },
        "machine": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000,
          "description": "Printer purchase price. $. The amount to allocate over its productive service hours."
        },
        "salvage": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000,
          "description": "Expected resale value. $. An assumption, not a guaranteed future selling price."
        },
        "lifeHours": {
          "type": "number",
          "minimum": 1,
          "maximum": 1000000,
          "description": "Productive service life. hours. Printing hours over which you spread the printer cost."
        },
        "maintenance": {
          "type": "number",
          "minimum": 0,
          "maximum": 10000,
          "description": "Maintenance reserve. $ / hour. Nozzles, belts, repairs, and other wear."
        },
        "laborRate": {
          "type": "number",
          "minimum": 0,
          "maximum": 10000,
          "description": "Your labor rate. $ / hour. Pay for your time, not just your filament."
        },
        "setup": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Setup time. min / order. Design prep and setup. Charged once for the whole order."
        },
        "post": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Finishing time. min / part. Support removal, sanding, and cleanup per successful part."
        },
        "failure": {
          "type": "number",
          "minimum": 0,
          "maximum": 95,
          "description": "Failed attempt rate. %. Repeatable material, machine, and energy costs are adjusted."
        },
        "packaging": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Packaging. $ / order. The total packaging cost for all parts in this order."
        },
        "shipping": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Delivery. $ / order. Your shipping cost. Enter 0 for local pickup."
        },
        "overhead": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Other costs. $ / order. Design licenses, consumables, or other costs not entered above."
        },
        "margin": {
          "type": "number",
          "minimum": 0,
          "maximum": 95,
          "description": "Target margin. % of price. Margin after modeled costs and fees, not markup or net profit."
        },
        "quote": {
          "type": "number",
          "minimum": 0,
          "maximum": 1000000000000,
          "description": "Your quoted price. $ / order. Total selling price before tax, including any delivery charge."
        },
        "actualGrams": {
          "type": [
            "number",
            "null"
          ],
          "minimum": 0,
          "maximum": 100000,
          "description": "Actual material used. g / order. Total across all successful and failed attempts."
        },
        "actualHours": {
          "type": [
            "number",
            "null"
          ],
          "minimum": 0,
          "maximum": 100000,
          "description": "Actual machine time. hours / order. Total printing time across all attempts and all parts."
        },
        "actualLabor": {
          "type": [
            "number",
            "null"
          ],
          "minimum": 0,
          "maximum": 100000,
          "description": "Actual hands-on time. min / order. All setup, finishing, and repeat labor for the order."
        },
        "feePercent": {
          "type": "number",
          "minimum": 0,
          "maximum": 50,
          "description": "Payment / platform fee. % of price. Combined percentage fees on the full quoted price."
        },
        "feeFixed": {
          "type": "number",
          "minimum": 0,
          "maximum": 100000,
          "description": "Fixed transaction fee. $ / order. One fixed fee for the order, not one per part."
        }
      }
    }
  },
  "allOf": [
    {
      "if": {
        "properties": {
          "actualsEnabled": {
            "const": true
          }
        }
      },
      "then": {
        "properties": {
          "fields": {
            "required": [
              "actualGrams",
              "actualHours",
              "actualLabor"
            ],
            "properties": {
              "actualGrams": {
                "type": "number"
              },
              "actualHours": {
                "type": "number"
              },
              "actualLabor": {
                "type": "number"
              }
            }
          }
        }
      }
    }
  ],
  "description": "Cross-field rules (resale <= purchase; margin + percentage fee < 100) and the total-price limit are enforced by calculateJob."
}