Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "All-in-One Business Management Lösung von Microsoft.",
"Environment": "Umgebung",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Name der Umgebung, zu der eine Verbindung hergestellt werden soll, z.B. 'Produktion' oder 'Sandbox'. Umweltnamen finden Sie im Business Central Admin Center.",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Melden Sie sich bei [Microsoft Azure Portal](https://portal.azure.com/).\n. Von der linken Seitenleiste gehen Sie zur **Microsoft Enfra ID**.\n3. Unter **Verwalten** klicken Sie auf **App-Registrierungen**.\n4. Klicken Sie auf die **Neue Registrierung** Schaltfläche.\n5. Geben Sie einen **Name** für Ihre App ein.\n6. Für **unterstützte Kontotypen**, auswählen:\n - **Konten in jedem Organisationsverzeichnis (jeder Microsoft-Entra-ID-Mieter - Multitenant) und persönlichen Microsoft-Konten**\n - Oder wählen Sie nach Ihren Anforderungen aus.\n7. In **Umleitungs-URI** wählen Sie **Web** und fügen Sie die angegebene URL hinzu.\n8. Klicken Sie auf **Registrieren**.\n9. Nach der Registrierung werden Sie zur Übersichtsseite der App weitergeleitet. Kopieren Sie die **Anwendungs-(Client)-ID**.\n10. Gehen Sie aus dem linken Menü zu **Zertifikate & Geheimnis**.\n - Unter **Kundengeheimnis**, klicken Sie **Kundengeheimnis**.\n - Geben Sie eine Beschreibung an, setzen Sie ein Ablaufdatum und klicken Sie auf **Hinzufügen**.\n - Kopieren Sie den **Wert** des Client-Geheimnisses (dies wird nicht wieder angezeigt).\n11. Gehe zu **API-Berechtigungen** vom linken Menü.\n - Klicke auf **Berechtigung hinzufügen**.\n - Wähle **Dynamics 365 Business Central** → **Delegierte Berechtigungen**.\n - Fügen Sie folgende Bereiche hinzu:\n - Finanzen. eadWrite.All\n - user_impersonation \n - Klicken Sie auf **Berechtigungen hinzufügen**.\n12. Kopieren Sie Ihre **Client-ID** und **Client-Geheimnis**.\n",
"Create Record": "Datensatz erstellen",
"Delete Record": "Datensatz löschen",
"Get Record": "Datensatz abrufen",
"Update Record": "Datensatz aktualisieren",
"Search Records": "Datensätze suchen",
"Custom API Call": "Eigener API-Aufruf",
"Creates a new record.": "Erstellt einen neuen Datensatz.",
"Deletes an existing record.": "Löscht einen existierenden Eintrag.",
"Retrieves the details of a record by it's ID.": "Ruft die Details eines Datensatzes durch seine ID ab.",
"Updates an existing record.": "Aktualisiert einen existierenden Datensatz.",
"Retrieves a list of records.": "Ruft eine Liste von Datensätzen ab.",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Company": "Firma",
"Record Type": "Datensatztyp",
"Record Fields": "Datensatzfelder",
"Record ID": "Datensatz-ID",
"Markdown": "Markdown",
"Filter Fields": "Felder filtern",
"Method": "Methode",
"Headers": "Kopfzeilen",
"Query Parameters": "Abfrageparameter",
"Body": "Körper",
"Response is Binary ?": "Antwort ist binär?",
"No Error on Failure": "Kein Fehler bei Fehler",
"Timeout (in seconds)": "Timeout (in Sekunden)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "Sie können nach allen Objektfeldern unten suchen. Wir liefern nur exakte Übereinstimmungen (Großschreibung ist wichtig!) auf alle angegebenen Werte.",
"Authorization headers are injected automatically from your connection.": "Autorisierungs-Header werden automatisch von Ihrer Verbindung injiziert.",
"Enable for files like PDFs, images, etc..": "Aktivieren für Dateien wie PDFs, Bilder, etc..",
"Bank Accounts": "Bankkonten",
"Contacts": "Kontakte",
"Currencies": "Währungen",
"Customers": "Kunden",
"Dispute Status": "Streitstatus",
"Employees": "Mitarbeiter",
"Item Categories": "Artikelkategorien",
"Items": "Items",
"Item Variants": "Artikelvarianten",
"Journals": "Zeitschriften",
"Locations": "Standorte",
"Payment Methods": "Zahlungsarten",
"Payment Terms": "Zahlungsbedingungen",
"Projects": "Projekte",
"Sales Invoice Lines": "Verkaufsrechnungszeilen",
"Sales Invoices": "Verkaufsrechnungen",
"Sales Order Lines": "Verkaufsauftragslinien",
"Sales Orders": "Verkaufsaufträge",
"Sales Quote Lines": "Verkaufsangebotslinien",
"Sales Quotes": "Verkaufsangebote",
"Shipment Methods": "Versandarten",
"Vendors": "Lieferant",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD",
"New or Updated Record": "Neuer oder aktualisierter Datensatz",
"Triggers when a new record is added or modified.": "Wird ausgelöst, wenn ein neuer Datensatz hinzugefügt oder geändert wird."
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "Solución de gestión de negocios todo en uno por Microsoft.",
"Environment": "Entorno",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Nombre del entorno al que conectar, por ejemplo, 'Producción' o 'Sandbox'. Los nombres de entorno se pueden encontrar en el Business Central Admin Center.",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and add the given URL.\n8. Click **Register**.\n9. After registration, youll be redirected to the apps overview page. Copy the **Application (client) ID**.\n10. From the left menu, go to **Certificates & secrets**.\n - Under **Client secrets**, click **New client secret**.\n - Provide a description, set an expiry, and click **Add**.\n - Copy the **Value** of the client secret (this will not be shown again).\n11. Go to **API permissions** from the left menu.\n - Click **Add a permission**.\n - Select **Dynamics 365 Business Central** → **Delegated permissions**.\n - Add the following scopes:\n - Financials.ReadWrite.All\n - user_impersonation\n - Click **Add permissions**.\n12. Copy your **Client ID** and **Client Secret**.\n",
"Create Record": "Crear registro",
"Delete Record": "Eliminar registro",
"Get Record": "Obtener registro",
"Update Record": "Actualizar registro",
"Search Records": "Buscar registros",
"Custom API Call": "Llamada API personalizada",
"Creates a new record.": "Crea un nuevo registro.",
"Deletes an existing record.": "Elimina un registro existente.",
"Retrieves the details of a record by it's ID.": "Recuperar los detalles de un registro por su ID.",
"Updates an existing record.": "Actualiza un registro existente.",
"Retrieves a list of records.": "Recuperar una lista de registros.",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Company": "Empresa",
"Record Type": "Tipo de registro",
"Record Fields": "Campos de registro",
"Record ID": "ID de registro",
"Markdown": "Markdown",
"Filter Fields": "Campos de filtro",
"Method": "Método",
"Headers": "Encabezados",
"Query Parameters": "Parámetros de consulta",
"Body": "Cuerpo",
"Response is Binary ?": "¿Respuesta es binaria?",
"No Error on Failure": "No hay ningún error en fallo",
"Timeout (in seconds)": "Tiempo de espera (en segundos)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "Puede buscar en cualquiera de los campos de propiedades a continuación. Devolveremos sólo coincidencias exactas (¡mayúsculas!) en todos los valores proporcionados.",
"Authorization headers are injected automatically from your connection.": "Las cabeceras de autorización se inyectan automáticamente desde tu conexión.",
"Enable for files like PDFs, images, etc..": "Activar para archivos como PDFs, imágenes, etc.",
"Bank Accounts": "Cuentas bancarias",
"Contacts": "Contactos",
"Currencies": "Monedas",
"Customers": "Clientes",
"Dispute Status": "Estado de disputa",
"Employees": "Empleados",
"Item Categories": "Categorías de artículos",
"Items": "Elementos",
"Item Variants": "Variantes de artículos",
"Journals": "Revistas",
"Locations": "Ubicaciones",
"Payment Methods": "Métodos de pago",
"Payment Terms": "Términos de pago",
"Projects": "Proyectos",
"Sales Invoice Lines": "Líneas de facturas de ventas",
"Sales Invoices": "Facturas de ventas",
"Sales Order Lines": "Líneas de pedidos de ventas",
"Sales Orders": "Pedidos de venta",
"Sales Quote Lines": "Líneas de cotización de ventas",
"Sales Quotes": "Cotizaciones de ventas",
"Shipment Methods": "Métodos de envío",
"Vendors": "Vendedores",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO",
"New or Updated Record": "Registro nuevo o actualizado",
"Triggers when a new record is added or modified.": "Dispara cuando se agrega o modifica un nuevo registro."
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "Solution de gestion globale de l'entreprise de Microsoft.",
"Environment": "Environnement",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Nom de l'environnement auquel se connecter, par exemple 'Production' ou 'Sandbox'. Les noms d'environnement peuvent être trouvés dans le Business Central Admin Center.",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and add the given URL.\n8. Click **Register**.\n9. After registration, youll be redirected to the apps overview page. Copy the **Application (client) ID**.\n10. From the left menu, go to **Certificates & secrets**.\n - Under **Client secrets**, click **New client secret**.\n - Provide a description, set an expiry, and click **Add**.\n - Copy the **Value** of the client secret (this will not be shown again).\n11. Go to **API permissions** from the left menu.\n - Click **Add a permission**.\n - Select **Dynamics 365 Business Central** → **Delegated permissions**.\n - Add the following scopes:\n - Financials.ReadWrite.All\n - user_impersonation\n - Click **Add permissions**.\n12. Copy your **Client ID** and **Client Secret**.\n",
"Create Record": "Créer un enregistrement",
"Delete Record": "Supprimer l'enregistrement",
"Get Record": "Obtenir un enregistrement",
"Update Record": "Mettre à jour l'enregistrement",
"Search Records": "Rechercher des enregistrements",
"Custom API Call": "Appel API personnalisé",
"Creates a new record.": "Crée un nouvel enregistrement.",
"Deletes an existing record.": "Supprime un enregistrement existant.",
"Retrieves the details of a record by it's ID.": "Récupère les détails d'un enregistrement par son ID.",
"Updates an existing record.": "Met à jour un enregistrement existant.",
"Retrieves a list of records.": "Récupère une liste d'enregistrements.",
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
"Company": "Entreprise",
"Record Type": "Type d'enregistrement",
"Record Fields": "Champs d'enregistrement",
"Record ID": "ID de l'enregistrement",
"Markdown": "Markdown",
"Filter Fields": "Filtrer les champs",
"Method": "Méthode",
"Headers": "En-têtes",
"Query Parameters": "Paramètres de requête",
"Body": "Corps",
"Response is Binary ?": "La réponse est Binaire ?",
"No Error on Failure": "Aucune erreur en cas d'échec",
"Timeout (in seconds)": "Délai d'attente (en secondes)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "Vous pouvez effectuer une recherche sur tous les champs de propriété ci-dessous. Nous retournerons uniquement les correspondances exactes (majuscules!) sur toutes les valeurs fournies.",
"Authorization headers are injected automatically from your connection.": "Les en-têtes d'autorisation sont injectés automatiquement à partir de votre connexion.",
"Enable for files like PDFs, images, etc..": "Activer pour les fichiers comme les PDFs, les images, etc.",
"Bank Accounts": "Comptes bancaires",
"Contacts": "Contacts",
"Currencies": "Devises",
"Customers": "Clients",
"Dispute Status": "Statut du litige",
"Employees": "Employés",
"Item Categories": "Catégories d'articles",
"Items": "Éléments",
"Item Variants": "Variantes d'objet",
"Journals": "Journaux",
"Locations": "Emplacements",
"Payment Methods": "Moyens de paiement",
"Payment Terms": "Conditions de paiement",
"Projects": "Projets",
"Sales Invoice Lines": "Lignes de facture de vente",
"Sales Invoices": "Factures de vente",
"Sales Order Lines": "Lignes de commande",
"Sales Orders": "Commandes de vente",
"Sales Quote Lines": "Lignes de devis de vente",
"Sales Quotes": "Devis de vente",
"Shipment Methods": "Méthodes d'expédition",
"Vendors": "Fournisseurs",
"GET": "OBTENIR",
"POST": "POSTER",
"PATCH": "PATCH",
"PUT": "EFFACER",
"DELETE": "SUPPRIMER",
"HEAD": "TÊTE",
"New or Updated Record": "Nouvel enregistrement ou mis à jour",
"Triggers when a new record is added or modified.": "Déclenche lorsqu'un nouvel enregistrement est ajouté ou modifié."
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "Microsoftによるオールインワンのビジネス管理ソリューション。",
"Environment": "環境",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "「Production」や「Sandbox」など、接続する環境の名前は、Business Central Admin Center に記載されています。",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and add the given URL.\n8. Click **Register**.\n9. After registration, youll be redirected to the apps overview page. Copy the **Application (client) ID**.\n10. From the left menu, go to **Certificates & secrets**.\n - Under **Client secrets**, click **New client secret**.\n - Provide a description, set an expiry, and click **Add**.\n - Copy the **Value** of the client secret (this will not be shown again).\n11. Go to **API permissions** from the left menu.\n - Click **Add a permission**.\n - Select **Dynamics 365 Business Central** → **Delegated permissions**.\n - Add the following scopes:\n - Financials.ReadWrite.All\n - user_impersonation\n - Click **Add permissions**.\n12. Copy your **Client ID** and **Client Secret**.\n",
"Create Record": "レコードを作成",
"Delete Record": "レコードを削除",
"Get Record": "レコードを取得",
"Update Record": "更新記録",
"Search Records": "レコードを検索",
"Custom API Call": "カスタムAPI通話",
"Creates a new record.": "新規レコードを作成",
"Deletes an existing record.": "既存のレコードを削除します。",
"Retrieves the details of a record by it's ID.": "IDでレコードの詳細を取得します。",
"Updates an existing record.": "既存のレコードを更新します。",
"Retrieves a list of records.": "レコードのリストを取得します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Company": "会社名",
"Record Type": "レコードタイプ",
"Record Fields": "レコードフィールド",
"Record ID": "レコードID",
"Markdown": "Markdown",
"Filter Fields": "フィルタフィールド",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "以下のすべてのプロパティフィールドを検索できます。提供されたすべての値には完全に一致する(大文字として)のみを返します。",
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
"Bank Accounts": "銀行アカウント",
"Contacts": "連絡先",
"Currencies": "通貨",
"Customers": "顧客",
"Dispute Status": "紛争状態",
"Employees": "従業員数",
"Item Categories": "アイテムカテゴリ",
"Items": "アイテム",
"Item Variants": "アイテムの種類",
"Journals": "日記",
"Locations": "場所",
"Payment Methods": "お支払い方法",
"Payment Terms": "支払い条件",
"Projects": "プロジェクト",
"Sales Invoice Lines": "販売請求書ライン",
"Sales Invoices": "販売請求書",
"Sales Order Lines": "注文明細線",
"Sales Orders": "受注商品",
"Sales Quote Lines": "見積もりライン",
"Sales Quotes": "販売の引用",
"Shipment Methods": "配送方法",
"Vendors": "仕入先",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭",
"New or Updated Record": "新規または更新されたレコード",
"Triggers when a new record is added or modified.": "新しいレコードが追加または変更されたときにトリガーします。"
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "Alles-in-één oplossing voor bedrijfsbeheer door Microsoft.",
"Environment": "Milieu",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Naam van de omgeving waarmee u verbinding wilt maken, bijvoorbeeld 'Productie' of 'Sandbox'. Omgevingsnamen zijn te vinden in het Business Central Admin Centrum.",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Log in bij [Microsoft Azure Portal](https://portal.azure.com/).\n. Ga naar **Microsoft Enfra ID**.\n3. Onder **Beheren**, klik op **App registraties**.\n4. Klik op de **Nieuwe registratie** knop.\n5. Voer een **Naam** in voor uw app.\n6. Voor **Ondersteunde accounttypen**, kies keuze:\n - **Accounts in elke map van de organisatie (Any Microsoft Entra ID-tenant - Multitenant) en persoonlijke Microsoft accounts**\n - Of selecteer gebaseerd op uw vereiste.\n7. In **Redirect URI**, selecteer **Web** en voeg de opgegeven URL toe.\n8. Klik **Register**.\n9. Na registratie wordt u doorverwezen naar de overzichtspagina. Kopieer de **Applicatie (client) ID**.\n10. Vanuit het linkermenu ga naar **Certificaten & geheimen**.\n - Onder **Client secrets**, klik op **Nieuwe client geheim**.\n - Geef een beschrijving, verloop, en klik **Toevoegen**.\n - Kopieer de **waarde** van de client secret (dit zal niet meer worden weergegeven).\n11. Ga naar **API permissies** in het linkermenu.\n - Klik **Voeg een permissie toe**.\n - Selecteer **Dynamics 365 Business Central** → **Delegated permissies**.\n - Voeg de volgende toepassingsgebieden toe:\n - Financiën. eadWrite.Alle\n - user_impersonation \n - Klik **Permissies toevoegen**.\n12. Kopieer uw **Client ID** en **Client Secret**.\n",
"Create Record": "Record Maken",
"Delete Record": "Record verwijderen",
"Get Record": "Krijg Record",
"Update Record": "Update Record",
"Search Records": "Records zoeken",
"Custom API Call": "Custom API Call",
"Creates a new record.": "Maakt een nieuw record aan.",
"Deletes an existing record.": "Verwijdert een bestaand record.",
"Retrieves the details of a record by it's ID.": "Haal de details van een record op via zijn ID.",
"Updates an existing record.": "Werkt een bestaand record bij.",
"Retrieves a list of records.": "Haal een lijst op met records.",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Company": "Bedrijfsnaam",
"Record Type": "Record type",
"Record Fields": "Record velden",
"Record ID": "Record ID",
"Markdown": "Markdown",
"Filter Fields": "Filter velden",
"Method": "Methode",
"Headers": "Kopteksten",
"Query Parameters": "Query parameters",
"Body": "Lichaam",
"Response is Binary ?": "Antwoord is binair?",
"No Error on Failure": "Geen fout bij fout",
"Timeout (in seconds)": "Time-out (in seconden)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "Je kunt zoeken op alle onderstaande eigenschappenvelden. We geven alleen exacte overeenkomsten terug (hoofdletters matters!) over alle verstrekte waarden.",
"Authorization headers are injected automatically from your connection.": "Autorisatie headers worden automatisch geïnjecteerd vanuit uw verbinding.",
"Enable for files like PDFs, images, etc..": "Inschakelen voor bestanden zoals PDF's, afbeeldingen etc..",
"Bank Accounts": "Bank rekeningen",
"Contacts": "Contactpersonen",
"Currencies": "Valuta's",
"Customers": "klanten",
"Dispute Status": "Status van aanvechten",
"Employees": "Werknemers",
"Item Categories": "Artikel categorieën",
"Items": "Artikelen",
"Item Variants": "Artikel varianten",
"Journals": "Logboeken",
"Locations": "Locaties",
"Payment Methods": "Betalingsmethoden",
"Payment Terms": "Betalingsvoorwaarden",
"Projects": "Projecten",
"Sales Invoice Lines": "Verkoop factuur regels",
"Sales Invoices": "Verkoop facturen",
"Sales Order Lines": "Verkooporder regels",
"Sales Orders": "Verkoop Orders",
"Sales Quote Lines": "Verkoop offerte regels",
"Sales Quotes": "Sales Offertes",
"Shipment Methods": "Verzending methoden",
"Vendors": "Leveranciers",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD",
"New or Updated Record": "Nieuwe of bijgewerkte record",
"Triggers when a new record is added or modified.": "Triggert wanneer een nieuwe record is toegevoegd of gewijzigd."
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "Solução completa de gerenciamento de negócios pela Microsoft.",
"Environment": "Seguros",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Nome do ambiente a se conectar, por exemplo, 'Produção' ou 'Sandbox'. Os nomes dos ambientes podem ser encontrados no Centro de Administração da Empresa",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Entre no [Microsoft Azure Portal](https://portal.azure.com/).\n. Na barra lateral esquerda, vá até **Microsoft Enfra ID**.\n3. Sob **Gerenciar**, clique em **Aplicativos registrados**.\n4. Clique no botão **Novo registro**.\n5. Digite um **Nome** para o seu aplicativo.\n6. Para **Tipos de conta suportados**, escolha:\n - **Contas em qualquer diretório organizacional (qualquer inquilino de ID da Microsoft Entra - Multitenant) e contas pessoais da Microsoft**\n - Ou selecione com base nos seus requisitos.\n7. Em **URI de redirecionamento**, selecione **Web** e adicione a URL fornecida.\n8. Clique em **Registrar**.\n9. Após o registro, você será redirecionado para a página de visão geral do aplicativo. Copie o **ID do aplicativo (cliente) **.\n10. No menu da esquerda, vá para **Certificados e segredos**.\n - Em **Segredos do cliente**, clique em **Novo segredo do cliente**.\n - Fornece uma descrição, define um vencimento e clique em **Adicionar**.\n - Copiar o **Valor** do segredo do cliente (isso não será exibido novamente).\n11. Vá para **permissões de API** no menu à esquerda.\n - Clique em **Adicionar uma permissão**.\n - Selecione **Dynamics 365 Business Central** → **Delegated permissions**.\n - Adicione os seguintes escopos:\n - Financeiros. eadWrite.All\n - user_impersonation \n - Clique em **Adicionar permissões**.\n12. Copie seu **ID do Cliente** e **Segredo do Cliente**.\n",
"Create Record": "Criar Registro",
"Delete Record": "Excluir registro",
"Get Record": "Obter Registro",
"Update Record": "Atualizar Registro",
"Search Records": "Buscar Registros",
"Custom API Call": "Chamada de API personalizada",
"Creates a new record.": "Cria um novo registro.",
"Deletes an existing record.": "Exclui um registro existente.",
"Retrieves the details of a record by it's ID.": "Recupera detalhes de um registro por ID.",
"Updates an existing record.": "Atualiza um registro existente.",
"Retrieves a list of records.": "Recupera uma lista de registros.",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Company": "Empresas",
"Record Type": "Tipo de Registro",
"Record Fields": "Recorde Campos",
"Record ID": "ID do Registro",
"Markdown": "Markdown",
"Filter Fields": "Campos de Filtro",
"Method": "Método",
"Headers": "Cabeçalhos",
"Query Parameters": "Parâmetros da consulta",
"Body": "Conteúdo",
"Response is Binary ?": "A resposta é binária ?",
"No Error on Failure": "Nenhum erro no Failure",
"Timeout (in seconds)": "Tempo limite (em segundos)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "Você pode pesquisar em todos os campos de propriedade abaixo. Retornaremos apenas correspondências exatas (importância de maiúsculas!) em todos os valores fornecidos.",
"Authorization headers are injected automatically from your connection.": "Os cabeçalhos de autorização são inseridos automaticamente a partir da sua conexão.",
"Enable for files like PDFs, images, etc..": "Habilitar para arquivos como PDFs, imagens, etc..",
"Bank Accounts": "Contas Bancárias",
"Contacts": "CONTATOS",
"Currencies": "Moedas",
"Customers": "clientes",
"Dispute Status": "Status da disputa",
"Employees": "Funcionários",
"Item Categories": "Categorias de Itens",
"Items": "Itens",
"Item Variants": "Variantes do Item",
"Journals": "Diários",
"Locations": "Alocações",
"Payment Methods": "Métodos de pagamento",
"Payment Terms": "Condições de pagamento",
"Projects": "Projetos",
"Sales Invoice Lines": "Linhas de Fatura",
"Sales Invoices": "Faturas de Vendas",
"Sales Order Lines": "Linhas de Pedidos Vendas",
"Sales Orders": "Pedidos de Venda",
"Sales Quote Lines": "Linhas de Cotação Vendas",
"Sales Quotes": "Cotações de Vendas",
"Shipment Methods": "Métodos de Envio",
"Vendors": "Fornecedores",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA",
"New or Updated Record": "Registro novo ou atualizado",
"Triggers when a new record is added or modified.": "Dispara quando um novo registro é adicionado ou modificado."
}

View File

@@ -0,0 +1,62 @@
{
"Microsoft Dynamics 365 Business Central": "Microsoft Dynamics 365 Business Central",
"All-in-one business management solution by Microsoft.": "Все решения для управления бизнесом от Microsoft.",
"Environment": "Среда",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Название окружения для подключения, например 'Производитель' или 'Песочница'. Названия окружающей среды можно найти в Центре бизнес-администрирования.",
"Create Record": "Создать запись",
"Delete Record": "Удалить запись",
"Get Record": "Получить запись",
"Update Record": "Обновить запись",
"Search Records": "Поиск записей",
"Custom API Call": "Пользовательский вызов API",
"Creates a new record.": "Создает новую запись.",
"Deletes an existing record.": "Удалить существующую запись.",
"Retrieves the details of a record by it's ID.": "Получает данные о записи по ее ID.",
"Updates an existing record.": "Обновление существующей записи.",
"Retrieves a list of records.": "Получает список записей.",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Company": "Компания",
"Record Type": "Тип записи",
"Record Fields": "Поля записи",
"Record ID": "ID записи",
"Markdown": "Markdown",
"Filter Fields": "Поля фильтра",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"Body": "Тело",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "Вы можете искать по любым и всем нижеследующим полям объекта. Мы вернем только точные совпадения (вопросы заглавности!) на все введенные значения.",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"Bank Accounts": "Банковские счета",
"Contacts": "Контакты",
"Currencies": "Валюты",
"Customers": "Клиенты",
"Dispute Status": "Статус спора",
"Employees": "Сотрудники",
"Item Categories": "Категории товаров",
"Items": "Items",
"Item Variants": "Варианты предметов",
"Journals": "Журналы",
"Locations": "Места",
"Payment Methods": "Способы оплаты",
"Payment Terms": "Условия оплаты",
"Projects": "Projects",
"Sales Invoice Lines": "Позиции счета продаж",
"Sales Invoices": "Счета продаж",
"Sales Order Lines": "Линии заказов на продажу",
"Sales Orders": "Заказы на продажу",
"Sales Quote Lines": "Строки смет продаж",
"Sales Quotes": "Продажи Предложения",
"Shipment Methods": "Способы доставки",
"Vendors": "Поставщики",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"New or Updated Record": "Новая или Обновленная запись",
"Triggers when a new record is added or modified.": "Триггеры при добавлении или изменении новой записи."
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "All-in-one business management solution by Microsoft.",
"Environment": "Environment",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and add the given URL.\n8. Click **Register**.\n9. After registration, youll be redirected to the apps overview page. Copy the **Application (client) ID**.\n10. From the left menu, go to **Certificates & secrets**.\n - Under **Client secrets**, click **New client secret**.\n - Provide a description, set an expiry, and click **Add**.\n - Copy the **Value** of the client secret (this will not be shown again).\n11. Go to **API permissions** from the left menu.\n - Click **Add a permission**.\n - Select **Dynamics 365 Business Central** → **Delegated permissions**.\n - Add the following scopes:\n - Financials.ReadWrite.All\n - user_impersonation\n - Click **Add permissions**.\n12. Copy your **Client ID** and **Client Secret**.\n",
"Create Record": "Create Record",
"Delete Record": "Delete Record",
"Get Record": "Get Record",
"Update Record": "Update Record",
"Search Records": "Search Records",
"Custom API Call": "Custom API Call",
"Creates a new record.": "Creates a new record.",
"Deletes an existing record.": "Deletes an existing record.",
"Retrieves the details of a record by it's ID.": "Retrieves the details of a record by it's ID.",
"Updates an existing record.": "Updates an existing record.",
"Retrieves a list of records.": "Retrieves a list of records.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Company": "Company",
"Record Type": "Record Type",
"Record Fields": "Record Fields",
"Record ID": "Record ID",
"Markdown": "Markdown",
"Filter Fields": "Filter Fields",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Bank Accounts": "Bank Accounts",
"Contacts": "Contacts",
"Currencies": "Currencies",
"Customers": "Customers",
"Dispute Status": "Dispute Status",
"Employees": "Employees",
"Item Categories": "Item Categories",
"Items": "Items",
"Item Variants": "Item Variants",
"Journals": "Journals",
"Locations": "Locations",
"Payment Methods": "Payment Methods",
"Payment Terms": "Payment Terms",
"Projects": "Projects",
"Sales Invoice Lines": "Sales Invoice Lines",
"Sales Invoices": "Sales Invoices",
"Sales Order Lines": "Sales Order Lines",
"Sales Orders": "Sales Orders",
"Sales Quote Lines": "Sales Quote Lines",
"Sales Quotes": "Sales Quotes",
"Shipment Methods": "Shipment Methods",
"Vendors": "Vendors",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New or Updated Record": "New or Updated Record",
"Triggers when a new record is added or modified.": "Triggers when a new record is added or modified."
}

View File

@@ -0,0 +1,62 @@
{
"Microsoft Dynamics 365 Business Central": "Microsoft Dynamics 365 Business Central",
"All-in-one business management solution by Microsoft.": "All-in-one business management solution by Microsoft.",
"Environment": "Environment",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.",
"Create Record": "Create Record",
"Delete Record": "Delete Record",
"Get Record": "Get Record",
"Update Record": "Update Record",
"Search Records": "Search Records",
"Custom API Call": "Custom API Call",
"Creates a new record.": "Creates a new record.",
"Deletes an existing record.": "Deletes an existing record.",
"Retrieves the details of a record by it's ID.": "Retrieves the details of a record by it's ID.",
"Updates an existing record.": "Updates an existing record.",
"Retrieves a list of records.": "Retrieves a list of records.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Company": "Company",
"Record Type": "Record Type",
"Record Fields": "Record Fields",
"Record ID": "Record ID",
"Markdown": "Markdown",
"Filter Fields": "Filter Fields",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Bank Accounts": "Bank Accounts",
"Contacts": "Contacts",
"Currencies": "Currencies",
"Customers": "Customers",
"Dispute Status": "Dispute Status",
"Employees": "Employees",
"Item Categories": "Item Categories",
"Items": "Items",
"Item Variants": "Item Variants",
"Journals": "Journals",
"Locations": "Locations",
"Payment Methods": "Payment Methods",
"Payment Terms": "Payment Terms",
"Projects": "Projects",
"Sales Invoice Lines": "Sales Invoice Lines",
"Sales Invoices": "Sales Invoices",
"Sales Order Lines": "Sales Order Lines",
"Sales Orders": "Sales Orders",
"Sales Quote Lines": "Sales Quote Lines",
"Sales Quotes": "Sales Quotes",
"Shipment Methods": "Shipment Methods",
"Vendors": "Vendors",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New or Updated Record": "New or Updated Record",
"Triggers when a new record is added or modified.": "Triggers when a new record is added or modified."
}

View File

@@ -0,0 +1,64 @@
{
"All-in-one business management solution by Microsoft.": "All-in-one business management solution by Microsoft.",
"Environment": "Environment",
"Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.": "Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.",
"\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and ad": "\n1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).\n2. From the left sidebar, go to **Microsoft Enfra ID**.\n3. Under **Manage**, click on **App registrations**.\n4. Click the **New registration** button.\n5. Enter a **Name** for your app.\n6. For **Supported account types**, choose:\n - **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**\n - Or select based on your requirement.\n7. In **Redirect URI**, select **Web** and add the given URL.\n8. Click **Register**.\n9. After registration, youll be redirected to the apps overview page. Copy the **Application (client) ID**.\n10. From the left menu, go to **Certificates & secrets**.\n - Under **Client secrets**, click **New client secret**.\n - Provide a description, set an expiry, and click **Add**.\n - Copy the **Value** of the client secret (this will not be shown again).\n11. Go to **API permissions** from the left menu.\n - Click **Add a permission**.\n - Select **Dynamics 365 Business Central** → **Delegated permissions**.\n - Add the following scopes:\n - Financials.ReadWrite.All\n - user_impersonation\n - Click **Add permissions**.\n12. Copy your **Client ID** and **Client Secret**.\n",
"Create Record": "Create Record",
"Delete Record": "Delete Record",
"Get Record": "Get Record",
"Update Record": "Update Record",
"Search Records": "Search Records",
"Custom API Call": "自定义 API 呼叫",
"Creates a new record.": "Creates a new record.",
"Deletes an existing record.": "Deletes an existing record.",
"Retrieves the details of a record by it's ID.": "Retrieves the details of a record by it's ID.",
"Updates an existing record.": "Updates an existing record.",
"Retrieves a list of records.": "Retrieves a list of records.",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Company": "Company",
"Record Type": "Record Type",
"Record Fields": "Record Fields",
"Record ID": "Record ID",
"Markdown": "Markdown",
"Filter Fields": "Filter Fields",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.": "You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.",
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Bank Accounts": "Bank Accounts",
"Contacts": "Contacts",
"Currencies": "Currencies",
"Customers": "Customers",
"Dispute Status": "Dispute Status",
"Employees": "Employees",
"Item Categories": "Item Categories",
"Items": "项目",
"Item Variants": "Item Variants",
"Journals": "Journals",
"Locations": "Locations",
"Payment Methods": "Payment Methods",
"Payment Terms": "Payment Terms",
"Projects": "项目",
"Sales Invoice Lines": "Sales Invoice Lines",
"Sales Invoices": "Sales Invoices",
"Sales Order Lines": "Sales Order Lines",
"Sales Orders": "Sales Orders",
"Sales Quote Lines": "Sales Quote Lines",
"Sales Quotes": "Sales Quotes",
"Shipment Methods": "Shipment Methods",
"Vendors": "Vendors",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色",
"New or Updated Record": "New or Updated Record",
"Triggers when a new record is added or modified.": "Triggers when a new record is added or modified."
}

View File

@@ -0,0 +1,91 @@
import {
createPiece,
OAuth2PropertyValue,
PieceAuth,
Property,
} from '@activepieces/pieces-framework';
import { createRecordAction } from './lib/actions/create-record.action';
import { getRecordAction } from './lib/actions/get-record.action';
import { updateRecordAction } from './lib/actions/update-record.action';
import { deleteRecordAction } from './lib/actions/delete-record.action';
import { newOrUpdatedRecordTrigger } from './lib/triggers/new-or-updated-record.trigger';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { searchRecordsAction } from './lib/actions/search-records.action';
import { PieceCategory } from '@activepieces/shared';
const authDesc = `
1. Sign in to [Microsoft Azure Portal](https://portal.azure.com/).
2. From the left sidebar, go to **Microsoft Enfra ID**.
3. Under **Manage**, click on **App registrations**.
4. Click the **New registration** button.
5. Enter a **Name** for your app.
6. For **Supported account types**, choose:
- **Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts**
- Or select based on your requirement.
7. In **Redirect URI**, select **Web** and add the given URL.
8. Click **Register**.
9. After registration, youll be redirected to the apps overview page. Copy the **Application (client) ID**.
10. From the left menu, go to **Certificates & secrets**.
- Under **Client secrets**, click **New client secret**.
- Provide a description, set an expiry, and click **Add**.
- Copy the **Value** of the client secret (this will not be shown again).
11. Go to **API permissions** from the left menu.
- Click **Add a permission**.
- Select **Dynamics 365 Business Central** → **Delegated permissions**.
- Add the following scopes:
- Financials.ReadWrite.All
- user_impersonation
- Click **Add permissions**.
12. Copy your **Client ID** and **Client Secret**.
`
export const businessCentralAuth = PieceAuth.OAuth2({
description:authDesc,
props: {
environment: Property.ShortText({
displayName: 'Environment',
description: `Name of the environment to connect to, e.g. 'Production' or 'Sandbox'. Environment names can be found in the Business Central Admin Center.`,
required: true,
defaultValue: 'Production',
}),
},
required: true,
scope: [
'https://api.businesscentral.dynamics.com/user_impersonation',
'https://api.businesscentral.dynamics.com/Financials.ReadWrite.All',
],
prompt: 'omit',
authUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
});
export const microsoftDynamics365BusinessCentral = createPiece({
displayName: 'Microsoft Dynamics 365 Business Central',
auth: businessCentralAuth,
description: 'All-in-one business management solution by Microsoft.',
categories: [PieceCategory.SALES_AND_CRM],
minimumSupportedRelease: '0.27.1',
logoUrl:
'https://cdn.activepieces.com/pieces/microsoft-dynamics-365-business-central.png',
authors: ['kishanprmr'],
actions: [
createRecordAction,
deleteRecordAction,
getRecordAction,
updateRecordAction,
searchRecordsAction,
createCustomApiCallAction({
auth: businessCentralAuth,
baseUrl: (auth) => {
return `https://api.businesscentral.dynamics.com/v2.0/${
(auth as OAuth2PropertyValue).props?.['environment']
}/api/v2.0`;
},
authMapping: async (auth) => ({
Authorization: `Bearer ${(auth as OAuth2PropertyValue).access_token}`,
}),
}),
],
triggers: [newOrUpdatedRecordTrigger],
});

View File

@@ -0,0 +1,59 @@
import { businessCentralAuth } from '../../';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps, formatRecordFields } from '../common';
import { makeClient } from '../common/client';
import { ACTION_ENTITY_DROPDOWN_OPTIONS } from '../common/constants';
export const createRecordAction = createAction({
auth: businessCentralAuth,
name: 'create-record',
displayName: 'Create Record',
description: 'Creates a new record.',
props: {
company_id: commonProps.company_id,
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: ACTION_ENTITY_DROPDOWN_OPTIONS,
},
}),
record_fields: commonProps.record_fields,
},
async run(context) {
const companyId = context.propsValue.company_id;
const recordType = context.propsValue.record_type;
const recordFields = context.propsValue.record_fields;
const formattedRecordFields = formatRecordFields(recordFields, recordType);
const client = makeClient(context.auth);
let endpoint;
switch (recordType) {
case 'itemVariants':
endpoint = `/companies(${companyId})/items(${recordFields['itemId']})/${recordType}`;
delete formattedRecordFields['itemId'];
break;
case 'salesInvoiceLines':
endpoint = `/companies(${companyId})/salesInvoices(${recordFields['salesInvoiceId']})/${recordType}`;
delete formattedRecordFields['salesInvoiceId'];
break;
case 'salesOrderLines':
endpoint = `/companies(${companyId})/salesOrders(${recordFields['salesOrderId']})/${recordType}`;
delete formattedRecordFields['salesOrderId'];
break;
case 'salesQuoteLines':
endpoint = `/companies(${companyId})/salesQuotes(${recordFields['salesQuoteId']})/${recordType}`;
delete formattedRecordFields['salesQuoteId'];
break;
default:
endpoint = `/companies(${companyId})/${recordType}`;
break;
}
return await client.createRecord(endpoint, formattedRecordFields);
},
});

View File

@@ -0,0 +1,34 @@
import { businessCentralAuth } from '../../';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps } from '../common';
import { makeClient } from '../common/client';
import { ACTION_ENTITY_DROPDOWN_OPTIONS } from '../common/constants';
export const deleteRecordAction = createAction({
auth: businessCentralAuth,
name: 'delete-record',
displayName: 'Delete Record',
description: 'Deletes an existing record.',
props: {
company_id: commonProps.company_id,
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: ACTION_ENTITY_DROPDOWN_OPTIONS,
},
}),
record_id: commonProps.record_id,
},
async run(context) {
const companyId = context.propsValue.company_id;
const recordType = context.propsValue.record_type;
const recordId = context.propsValue.record_id;
const client = makeClient(context.auth);
const endpoint = `/companies(${companyId})/${recordType}(${recordId})`;
return await client.deleteRecord(endpoint);
},
});

View File

@@ -0,0 +1,35 @@
import { businessCentralAuth } from '../../';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps } from '../common';
import { makeClient } from '../common/client';
import { ACTION_ENTITY_DROPDOWN_OPTIONS } from '../common/constants';
export const getRecordAction = createAction({
auth: businessCentralAuth,
name: 'get-record',
displayName: 'Get Record',
description: `Retrieves the details of a record by it's ID.`,
props: {
company_id: commonProps.company_id,
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: ACTION_ENTITY_DROPDOWN_OPTIONS,
},
}),
record_id: commonProps.record_id,
},
async run(context) {
const companyId = context.propsValue.company_id;
const recordType = context.propsValue.record_type;
const recordId = context.propsValue.record_id;
const client = makeClient(context.auth);
const endpoint = `/companies(${companyId})/${recordType}(${recordId})`;
return await client.getRecord(endpoint);
},
});

View File

@@ -0,0 +1,46 @@
import { businessCentralAuth } from '../../';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps } from '../common';
import { makeClient } from '../common/client';
import { TRIGGER_ENTITY_DROPDOWN_OPTIONS } from '../common/constants';
export const searchRecordsAction = createAction({
auth: businessCentralAuth,
name: 'search-records',
displayName: 'Search Records',
description: 'Retrieves a list of records.',
props: {
company_id: commonProps.company_id,
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: TRIGGER_ENTITY_DROPDOWN_OPTIONS,
},
}),
markdown: Property.MarkDown({
value: `You can search on any and all of the property fields below. We'll return only exact matches (capitalization matters!) on all values provided.`,
}),
record_filter_fields: commonProps.record_filter_fields,
},
async run(context) {
const companyId = context.propsValue.company_id;
const recordType = context.propsValue.record_type;
const recordFilterFields = context.propsValue.record_filter_fields;
const filterFieldsArray = [];
for (const key in recordFilterFields) {
if (recordFilterFields[key]) {
filterFieldsArray.push(`${key} eq '${recordFilterFields[key]}'`);
}
}
const client = makeClient(context.auth);
return await client.filterRecords(companyId, recordType, {
$filter: filterFieldsArray.join(' and '),
});
},
});

View File

@@ -0,0 +1,60 @@
import { businessCentralAuth } from '../../';
import { createAction, Property } from '@activepieces/pieces-framework';
import { commonProps, formatRecordFields } from '../common';
import { makeClient } from '../common/client';
import { ACTION_ENTITY_DROPDOWN_OPTIONS } from '../common/constants';
export const updateRecordAction = createAction({
auth: businessCentralAuth,
name: 'update-record',
displayName: 'Update Record',
description: 'Updates an existing record.',
props: {
company_id: commonProps.company_id,
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: ACTION_ENTITY_DROPDOWN_OPTIONS,
},
}),
record_id: commonProps.record_id,
record_fields: commonProps.record_fields,
},
async run(context) {
const companyId = context.propsValue.company_id;
const recordType = context.propsValue.record_type;
const recordId = context.propsValue.record_id;
const recordFields = context.propsValue.record_fields;
const formattedRecordFields = formatRecordFields(recordFields, recordType);
const client = makeClient(context.auth);
let endpoint;
switch (recordType) {
case 'itemVariants':
endpoint = `/companies(${companyId})/items(${recordFields['itemId']})/${recordType}(${recordId})`;
delete formattedRecordFields['itemId'];
break;
case 'salesInvoiceLines':
endpoint = `/companies(${companyId})/salesInvoices(${recordFields['salesInvoiceId']})/${recordType}(${recordId})`;
delete formattedRecordFields['salesInvoiceId'];
break;
case 'salesOrderLines':
endpoint = `/companies(${companyId})/salesOrders(${recordFields['salesOrderId']})/${recordType}(${recordId})`;
delete formattedRecordFields['salesOrderId'];
break;
case 'salesQuoteLines':
endpoint = `/companies(${companyId})/salesQuotes(${recordFields['salesQuoteId']})/${recordType}(${recordId})`;
delete formattedRecordFields['salesQuoteId'];
break;
default:
endpoint = `/companies(${companyId})/${recordType}(${recordId})`;
break;
}
return await client.updateRecord(endpoint, formattedRecordFields);
},
});

View File

@@ -0,0 +1,120 @@
import { businessCentralAuth } from '../../';
import {
HttpMessageBody,
HttpMethod,
QueryParams,
httpClient,
HttpRequest,
AuthenticationType,
HttpHeaders,
} from '@activepieces/pieces-common';
import { AppConnectionValueForAuthProperty, PiecePropValueSchema } from '@activepieces/pieces-framework';
interface ListAPIResponse<T> {
'@odata.context': string;
value: Array<T>;
}
interface CompanyResponse {
id: string;
name: string;
}
export type filterParams = Record<
string,
string | number | string[] | undefined
>;
export class BusinessCentralAPIClient {
constructor(private environment: string, private accessToken: string) {}
async makeRequest<T extends HttpMessageBody>(
method: HttpMethod,
resourceUri: string,
query?: filterParams,
body: any | undefined = undefined
): Promise<T> {
const baseUrl = `https://api.businesscentral.dynamics.com/v2.0/${this.environment}/api/v2.0`;
const params: QueryParams = {};
const headers: HttpHeaders = {};
if (query) {
for (const [key, value] of Object.entries(query)) {
if (value !== null && value !== undefined) {
params[key] = String(value);
}
}
}
if (method === HttpMethod.PATCH || method === HttpMethod.DELETE) {
headers['If-Match'] = '*';
}
const request: HttpRequest = {
method: method,
url: baseUrl + resourceUri,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: this.accessToken,
},
headers,
queryParams: params,
body: body,
};
const response = await httpClient.sendRequest<T>(request);
return response.body;
}
async listCompanies(): Promise<ListAPIResponse<CompanyResponse>> {
return await this.makeRequest(HttpMethod.GET, '/companies');
}
async createRecord(endpoint: string, request: Record<string, any>) {
return await this.makeRequest(
HttpMethod.POST,
endpoint,
undefined,
request
);
}
async updateRecord(endpoint: string, request: Record<string, any>) {
return await this.makeRequest(
HttpMethod.PATCH,
endpoint,
undefined,
request
);
}
async getRecord(endpoint: string) {
return await this.makeRequest(HttpMethod.GET, endpoint);
}
async deleteRecord(endpoint: string) {
return await this.makeRequest(HttpMethod.DELETE, endpoint);
}
async filterRecords(
companyId: string,
recordType: string,
params: filterParams
): Promise<ListAPIResponse<Record<string, unknown>>> {
return await this.makeRequest(
HttpMethod.GET,
`/companies(${companyId})/${recordType}`,
params
);
}
}
export function makeClient(
auth: AppConnectionValueForAuthProperty<typeof businessCentralAuth>
) {
const client = new BusinessCentralAPIClient(
auth.props?.['environment'] as string ?? '',
auth.access_token
);
return client;
}

View File

@@ -0,0 +1,98 @@
export const ACTION_ENTITY_DROPDOWN_OPTIONS = [
{
label: 'Bank Accounts',
value: 'bankAccounts',
},
{
label: 'Contacts',
value: 'contacts',
},
{
label: 'Currencies',
value: 'currencies',
},
{
label: 'Customers',
value: 'customers',
},
{
label: 'Dispute Status',
value: 'disputeStatus',
},
{
label: 'Employees',
value: 'employees',
},
{
label: 'Item Categories',
value: 'itemCategories',
},
{
label: 'Items',
value: 'items',
},
{
label: 'Item Variants',
value: 'itemVariants',
},
{
label: 'Journals',
value: 'journals',
},
{
label: 'Locations',
value: 'locations',
},
{
label: 'Payment Methods',
value: 'paymentMethods',
},
{
label: 'Payment Terms',
value: 'paymentTerms',
},
{
label: 'Projects',
value: 'projects',
},
{
label: 'Sales Invoice Lines',
value: 'salesInvoiceLines',
},
{
label: 'Sales Invoices',
value: 'salesInvoices',
},
{
label: 'Sales Order Lines',
value: 'salesOrderLines',
},
{
label: 'Sales Orders',
value: 'salesOrders',
},
{
label: 'Sales Quote Lines',
value: 'salesQuoteLines',
},
{
label: 'Sales Quotes',
value: 'salesQuotes',
},
{
label: 'Shipment Methods',
value: 'shipmentMethods',
},
{
label: 'Vendors',
value: 'vendors',
},
];
export const TRIGGER_ENTITY_DROPDOWN_OPTIONS =
ACTION_ENTITY_DROPDOWN_OPTIONS.filter(
(option) =>
!['salesQuoteLines', 'salesOrderLines', 'salesInvoiceLines'].includes(
option.value
)
);

View File

@@ -0,0 +1,376 @@
import { businessCentralAuth } from '../..';
import {
DropdownOption,
DynamicPropsValue,
PiecePropValueSchema,
Property,
} from '@activepieces/pieces-framework';
import { makeClient } from './client';
import { ACTION_ENTITY_DROPDOWN_OPTIONS } from './constants';
import { customersEntityProps } from './props/customers.entity';
import { bankAccountsEntityProps } from './props/bankAccounts.entity';
import { contactsEntityProps } from './props/contacts.entity';
import {
currenciesEntityNumberProps,
currenciesEntityProps,
} from './props/currencies.entity';
import { disputeStatusEntityProps } from './props/disputeStatus.entity';
import { employeesEntityProps } from './props/employees.entity';
import { vendorsEntityProps } from './props/vendors.entity';
import { journalsEntityProps } from './props/journals.entity';
import { locationsEntityProps } from './props/locations.entity';
import { paymentMethodsEntityProps } from './props/paymentMethods.entity';
import {
paymentTermsEntityNumberProps,
paymentTermsEntityProps,
} from './props/paymentTerms.entity';
import { projectsEntityProps } from './props/projects.entity';
import { itemCategoriesEntityProps } from './props/itemCategories.entity';
import { itemsEntityNumberProps, itemsEntityProps } from './props/items.entity';
import { itemVariantsEntityProps } from './props/itemVariants.entity';
import {
salesOrderLinesEntityNumberProps,
salesOrdersLinesEntityProps,
} from './props/salesOrderLines.entity';
import {
salesInvoiceLinesEntityNumberProps,
salesInvoiceLinesEntityProps,
} from './props/salesInvoiceLines.entity';
import {
salesQuoteLinesEntityNumberProps,
salesQuoteLinesEntityProps,
} from './props/salesQuoteLines.entity';
import { shipmentMethodsEntityProps } from './props/shipmentMethods.entity';
import { EntityProp } from './types';
import { salesInvoicesEntityProps } from './props/salesInvoices.entity';
import { salesOrdersEntityProps } from './props/salesOrders.entity';
import { salesQuotesEntityProps } from './props/salesQuotes.entity';
export const commonProps = {
company_id: Property.Dropdown({
auth: businessCentralAuth,
displayName: 'Company',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect account first',
};
}
const authValue = auth
const client = makeClient(authValue);
const res = await client.listCompanies();
const options: DropdownOption<string>[] = [];
for (const company of res.value) {
options.push({ label: company.name, value: company.id });
}
return {
disabled: false,
options,
};
},
}),
record_id: Property.ShortText({
displayName: 'Record ID',
required: true,
}),
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: ACTION_ENTITY_DROPDOWN_OPTIONS,
},
}),
record_fields: Property.DynamicProperties({
auth: businessCentralAuth,
displayName: 'Record Fields',
refreshers: ['company_id', 'record_type'],
required: true,
props: async ({ auth, company_id, record_type }) => {
if (!auth) return {};
if (!company_id) return {};
if (!record_type) return {};
const recordType = record_type as unknown as string;
const companyId = company_id as unknown as string;
const authValue = auth
const client = makeClient(authValue);
const fields: DynamicPropsValue = {};
// fetch entity prop schema
const entitySchema = getEntityPropSchema(recordType);
for (const prop of entitySchema) {
switch (prop.type) {
case 'text':
fields[prop.name] = Property.ShortText({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
case 'multi_text':
fields[prop.name] = Property.LongText({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
case 'date':
fields[prop.name] = Property.DateTime({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
case 'number':
fields[prop.name] = Property.Number({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
case 'boolean':
fields[prop.name] = Property.Checkbox({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
case 'static_select':
fields[prop.name] = Property.StaticDropdown({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
options: {
disabled: false,
options: prop.options ?? [],
},
});
break;
case 'static_multi_select':
fields[prop.name] = Property.StaticMultiSelectDropdown({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
options: {
disabled: false,
options: prop.options ?? [],
},
});
break;
case 'dynamic_multi_select':
case 'dynamic_select':
{
const propType =
prop.type === 'dynamic_select'
? Property.StaticDropdown
: Property.StaticMultiSelectDropdown;
const response = await client.filterRecords(
companyId,
prop.options.sourceFieldSlug,
{
$select: `${prop.options.labelField},id`,
}
);
const options: DropdownOption<string>[] = [];
for (const option of response.value) {
options.push({
label: option[prop.options.labelField] as string,
value: option['id'] as string,
});
}
fields[prop.name] = propType({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
options: {
disabled: false,
options,
},
});
}
break;
default:
break;
}
}
return fields;
},
}),
record_filter_fields: Property.DynamicProperties({
auth: businessCentralAuth,
displayName: 'Filter Fields',
refreshers: ['company_id', 'record_type'],
required: true,
props: async ({ auth, company_id, record_type }) => {
if (!auth) return {};
if (!company_id) return {};
if (!record_type) return {};
const recordType = record_type as unknown as string;
const fields: DynamicPropsValue = {};
// fetch entity prop schema
const entitySchema = getEntityPropSchema(recordType);
// currently only support text fields
for (const prop of entitySchema) {
switch (prop.type) {
case 'text':
fields[prop.name] = Property.ShortText({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
case 'multi_text':
fields[prop.name] = Property.LongText({
displayName: prop.displayName,
description: prop.description,
required: prop.isRequired,
});
break;
default:
break;
}
}
return fields;
},
}),
};
export function formatRecordFields(
recordFields: DynamicPropsValue,
recordType: string
) {
const numberFields = [];
switch (recordType) {
case 'currencies':
numberFields.push(...currenciesEntityNumberProps);
break;
case 'items':
numberFields.push(...itemsEntityNumberProps);
break;
case 'salesInvoiceLines':
numberFields.push(...salesInvoiceLinesEntityNumberProps);
break;
case 'salesOrders':
numberFields.push(...salesOrderLinesEntityNumberProps);
break;
case 'salesOrderLines':
numberFields.push(...salesOrderLinesEntityNumberProps);
break;
case 'salesQuoteLines':
numberFields.push(...salesQuoteLinesEntityNumberProps);
break;
case 'paymentTerms':
numberFields.push(...paymentTermsEntityNumberProps);
break;
default:
break;
}
const formattedRecordFields: DynamicPropsValue = {};
for (const key in recordFields) {
if (recordFields[key] !== undefined) {
if (numberFields.includes(key)) {
formattedRecordFields[key] = Number(recordFields[key]);
} else {
formattedRecordFields[key] = recordFields[key];
}
}
}
return formattedRecordFields;
}
export function getEntityPropSchema(recordType: string): EntityProp[] {
let entitySchema: EntityProp[] = [];
// fetch entity prop schema
switch (recordType) {
case 'bankAccounts':
entitySchema = bankAccountsEntityProps;
break;
case 'contacts':
entitySchema = contactsEntityProps;
break;
case 'currencies':
entitySchema = currenciesEntityProps;
break;
case 'customers':
entitySchema = customersEntityProps;
break;
case 'disputeStatus':
entitySchema = disputeStatusEntityProps;
break;
case 'employees':
entitySchema = employeesEntityProps;
break;
case 'itemCategories':
entitySchema = itemCategoriesEntityProps;
break;
case 'items':
entitySchema = itemsEntityProps;
break;
case 'itemVariants':
entitySchema = itemVariantsEntityProps;
break;
case 'journals':
entitySchema = journalsEntityProps;
break;
case 'locations':
entitySchema = locationsEntityProps;
break;
case 'paymentTerms':
entitySchema = paymentTermsEntityProps;
break;
case 'paymentMethods':
entitySchema = paymentMethodsEntityProps;
break;
case 'projects':
entitySchema = projectsEntityProps;
break;
case 'salesInvoiceLines':
entitySchema = salesInvoiceLinesEntityProps;
break;
case 'salesInvoices':
entitySchema = salesInvoicesEntityProps;
break;
case 'salesOrderLines':
entitySchema = salesOrdersLinesEntityProps;
break;
case 'salesOrders':
entitySchema = salesOrdersEntityProps;
break;
case 'salesQuoteLines':
entitySchema = salesQuoteLinesEntityProps;
break;
case 'salesQuotes':
entitySchema = salesQuotesEntityProps;
break;
case 'shipmentMethods':
entitySchema = shipmentMethodsEntityProps;
break;
case 'vendors':
entitySchema = vendorsEntityProps;
break;
default:
break;
}
return entitySchema;
}

View File

@@ -0,0 +1,34 @@
import { EntityProp } from '../types';
export const bankAccountsEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
type: 'text',
isRequired: false,
},
{
name: 'bankAccountNumber',
displayName: 'Bank Account Number',
type: 'text',
isRequired: false,
},
{
name: 'blocked',
displayName: 'Blocked ?',
type: 'boolean',
isRequired: false,
},
{
name: 'iban',
displayName: 'IBAN',
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,110 @@
import { EntityProp } from '../types';
export const contactsEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
type: 'text',
isRequired: false,
},
{
name: 'type',
displayName: 'Type',
type: 'static_select',
isRequired: false,
options: [
{
label: 'Person',
value: 'Person',
},
{
label: 'Company',
value: 'Company',
},
],
},
{
name: 'jobTitle',
displayName: 'Job Title',
type: 'text',
isRequired: false,
},
{
name: 'addressLine1',
displayName: 'Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'addressLine2',
displayName: 'Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'city',
displayName: 'City',
type: 'text',
isRequired: false,
},
{
name: 'state',
displayName: 'State',
type: 'text',
isRequired: false,
},
{
name: 'country',
displayName: 'Country',
type: 'text',
isRequired: false,
},
{
name: 'postalCode',
displayName: 'Postal Code',
type: 'text',
isRequired: false,
},
{
name: 'phoneNumber',
displayName: 'Phone Number',
type: 'text',
isRequired: false,
},
{
name: 'mobilePhoneNumber',
displayName: 'Mobile Number',
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
type: 'text',
isRequired: false,
},
{
name: 'website',
displayName: 'Website',
type: 'text',
isRequired: false,
},
{
name: 'privacyBlocked',
displayName: 'Privacy Blocked?',
type: 'boolean',
isRequired: false,
},
{
name: 'taxRegistrationNumber',
displayName: 'Tax Registration Number',
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,32 @@
import { EntityProp } from '../types';
export const currenciesEntityProps: EntityProp[] = [
{
name: 'displayName',
displayName: 'Display Name',
type: 'text',
isRequired: false,
},
{
name: 'code',
displayName: 'Code',
type: 'text',
isRequired: false,
},
{
name: 'amountDecimalPlaces',
displayName: 'Amount Decimal Places',
description:
'Specifies the number of decimal places the system will display on amounts for this currency.',
type: 'text',
isRequired: false,
},
{
name: 'amountRoundingPrecision',
displayName: 'Amount Rounding Precision',
type: 'number',
isRequired: false,
},
];
export const currenciesEntityNumberProps = ['amountRoundingPrecision'];

View File

@@ -0,0 +1,126 @@
import { EntityProp } from '../types';
export const customersEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
type: 'text',
isRequired: false,
},
{
name: 'type',
displayName: 'Type',
type: 'static_select',
isRequired: false,
options: [
{
label: 'Person',
value: 'Person',
},
{
label: 'Company',
value: 'Company',
},
],
},
{
name: 'addressLine1',
displayName: 'Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'addressLine2',
displayName: 'Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'city',
displayName: 'City',
type: 'text',
isRequired: false,
},
{
name: 'state',
displayName: 'State',
type: 'text',
isRequired: false,
},
{
name: 'country',
displayName: 'Country',
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
type: 'text',
isRequired: false,
},
{
name: 'website',
displayName: 'Website',
type: 'text',
isRequired: false,
},
{
name: 'taxLiable',
displayName: 'Tax Liable?',
type: 'boolean',
isRequired: false,
},
{
name: 'currencyId',
displayName: 'Currency ID',
type: 'dynamic_select',
isRequired: false,
options: {
labelField: 'code',
sourceFieldSlug: 'currencies',
},
},
{
name: 'currencyCode',
displayName: 'Currency Code',
type: 'text',
isRequired: false,
},
{
name: 'paymentTermsId',
displayName: 'Payment Terms ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentTerms',
labelField: 'code',
},
},
{
name: 'shipmentMethodId',
displayName: 'Shipment Method ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'shipmentMethods',
labelField: 'code',
},
},
{
name: 'paymentMethodId',
displayName: 'Payment Method ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentMethods',
labelField: 'code',
},
},
];

View File

@@ -0,0 +1,18 @@
import { EntityProp } from '../types';
export const disputeStatusEntityProps: EntityProp[] = [
{
name: 'code',
displayName: 'Code',
description: 'The code of the dispute status.',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
description: `Specifies the dispute status's name. This name will appear on all sales documents for the dispute status.`,
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,127 @@
import { EntityProp } from '../types';
export const employeesEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'givenName',
displayName: 'First Name',
type: 'text',
isRequired: false,
},
{
name: 'middleName',
displayName: 'Middle Name',
type: 'text',
isRequired: false,
},
{
name: 'surname',
displayName: 'Last Name',
type: 'text',
isRequired: false,
},
{
name: 'jobTitle',
displayName: 'Job Title',
type: 'text',
isRequired: false,
},
{
name: 'addressLine1',
displayName: 'Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'addressLine2',
displayName: 'Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'city',
displayName: 'City',
type: 'text',
isRequired: false,
},
{
name: 'state',
displayName: 'State',
type: 'text',
isRequired: false,
},
{
name: 'country',
displayName: 'Country',
type: 'text',
isRequired: false,
},
{
name: 'postalCode',
displayName: 'Postal Code',
type: 'text',
isRequired: false,
},
{
name: 'phoneNumber',
displayName: 'Phone Number',
type: 'text',
isRequired: false,
},
{
name: 'mobilePhone',
displayName: 'Mobile Number',
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
type: 'text',
isRequired: false,
},
{
name: 'personalEmail',
displayName: 'Personal Email',
type: 'text',
isRequired: false,
},
{
name: 'status',
displayName: 'Status',
type: 'static_select',
description: 'Specifies the status of the employee.',
isRequired: false,
options: [
{
label: 'Active',
value: 'Active',
},
{
label: 'Inactive',
value: 'Inactive',
},
{
label: 'Terminated',
value: 'Terminated',
},
],
},
{
name: 'birthDate',
displayName: 'Birth Date',
type: 'date',
isRequired: false,
},
{
name: 'employmentDate',
displayName: 'Employment Date',
type: 'date',
isRequired: false,
},
];

View File

@@ -0,0 +1,20 @@
import { EntityProp } from '../types';
export const itemCategoriesEntityProps: EntityProp[] = [
{
name: 'code',
displayName: 'Code',
description: 'The code of the item category.',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
description:
"Specifies the item category's name. This name will appear on all sales documents for the item category.",
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,28 @@
import { EntityProp } from '../types';
export const itemVariantsEntityProps: EntityProp[] = [
{
name: 'itemId',
displayName: 'Item ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'items',
labelField: 'number',
},
},
{
name: 'code',
displayName: 'Code',
description: 'The code of the item variant.',
type: 'text',
isRequired: false,
},
{
name: 'description',
displayName: 'Description',
description: 'Specifies the description of the item variant.',
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,109 @@
import { EntityProp } from '../types';
export const itemsEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
type: 'text',
isRequired: false,
},
{
name: 'type',
displayName: 'Type',
type: 'static_select',
isRequired: false,
options: [
{ label: 'Inventory', value: 'Inventory' },
{ label: 'Service', value: 'Service' },
{ label: 'Non-Inventory', value: 'Non-Inventory' },
],
},
{
name: 'blocked',
displayName: 'Blocked?',
type: 'boolean',
isRequired: false,
},
{
name: 'itemCategoryId',
displayName: 'Item Category ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'itemCategories',
labelField: 'code',
},
},
{
name: 'itemCategoryCode',
displayName: 'Item Category Code',
type: 'text',
isRequired: false,
},
{
name: 'gtin',
displayName: 'GTIN',
type: 'text',
isRequired: false,
},
{
name: 'unitPrice',
displayName: 'Unit Price',
type: 'number',
isRequired: false,
},
{
name: 'priceIncludesTax',
displayName: 'Price Includes Tax?',
description:
'Specifies that the unitPrice includes tax. Set to true, if unitPrice includes tax.',
type: 'boolean',
isRequired: false,
},
{
name: 'unitCost',
displayName: 'Unit Cost',
type: 'number',
isRequired: false,
},
{
name: 'baseUnitOfMeasureId',
displayName: 'Basic Unit of Measure ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'unitsOfMeasure',
labelField: 'code',
},
},
{
name: 'baseUnitOfMeasureCode',
displayName: 'Basic Unit of Measure Code',
isRequired: false,
type: 'text',
},
{
name: 'taxGroupId',
displayName: 'Tax Group ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'taxGroups',
labelField: 'code',
},
},
{
name: 'taxGroupCode',
displayName: 'Tax Group Code',
isRequired: false,
type: 'text',
},
];
export const itemsEntityNumberProps = ['unitPrice', 'unitCost'];

View File

@@ -0,0 +1,25 @@
import { EntityProp } from '../types';
export const journalsEntityProps: EntityProp[] = [
{
name: 'code',
displayName: 'Code',
description: 'The code of the journal.',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
description:
"Specifies the journal's name. This name will appear on all sales documents for the journal.",
type: 'text',
isRequired: false,
},
{
name: 'balancingAccountNumber',
displayName: 'Balancing Account Number',
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,72 @@
import { EntityProp } from '../types';
export const locationsEntityProps: EntityProp[] = [
{
name: 'code',
displayName: 'Code',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
description:
"Specifies the location's name. This name will appear on all sales documents for the location.",
type: 'text',
isRequired: false,
},
{
name: 'addressLine1',
displayName: 'Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'addressLine2',
displayName: 'Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'city',
displayName: 'City',
type: 'text',
isRequired: false,
},
{
name: 'state',
displayName: 'State',
type: 'text',
isRequired: false,
},
{
name: 'country',
displayName: 'Country',
type: 'text',
isRequired: false,
},
{
name: 'postalCode',
displayName: 'Postal Code',
type: 'text',
isRequired: false,
},
{
name: 'phoneNumber',
displayName: 'Phone Number',
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
type: 'text',
isRequired: false,
},
{
name: 'website',
displayName: 'Website',
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,20 @@
import { EntityProp } from '../types';
export const paymentMethodsEntityProps: EntityProp[] = [
{
name: 'code',
displayName: 'Code',
description: 'The code of the payment method.',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
description:
"Specifies the payment method's name. This name will appear on all sales documents for the payment method.",
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,51 @@
import { EntityProp } from '../types';
export const paymentTermsEntityProps: EntityProp[] = [
{
name: 'code',
displayName: 'Code',
description: 'The code of the payment term.',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
description:
"Specifies the payment term's name. This name will appear on all sales documents for the payment term.",
type: 'text',
isRequired: false,
},
{
name: 'dueDateCalculation',
displayName: 'Due Date Calculation',
description:
'Specifies the formula that is used to calculate the date that a payment must be made.',
type: 'text',
isRequired: false,
},
{
name: 'discountDateCalculation',
displayName: 'Discount Date Calculation',
description:
'Specifies the formula that is used to calculate the date that a payment must be made in order to obtain a discount.',
type: 'text',
isRequired: false,
},
{
name: 'discountPercent',
displayName: 'Discount Percent',
type: 'number',
isRequired: false,
},
{
name: 'calculateDiscountOnCreditMemos',
displayName: 'Calc. Pmt. Disc. on Credit Memos',
type: 'boolean',
description:
'Specifies if the discount should be applied to payment term. True indicates a discount will be given, false indicates a discount will not be given.',
isRequired: false,
},
];
export const paymentTermsEntityNumberProps = ['discountPercent'];

View File

@@ -0,0 +1,20 @@
import { EntityProp } from '../types';
export const projectsEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
description: 'Specifies the number of the project.',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display name',
description:
"Specifies the project's name. This name will appear on all sales documents for the project.",
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,141 @@
import { EntityProp } from '../types';
//https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesinvoiceline
export const salesInvoiceLinesEntityProps: EntityProp[] = [
{
name: 'salesInvoiceId',
displayName: 'Sales Invoice ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'salesInvoices',
labelField: 'number',
},
},
{
name: 'lineType',
displayName: 'Type',
type: 'static_select',
isRequired: false,
options: [
// {
// label: 'Comment',
// value: 'Comment',
// },
// {
// label: 'Account',
// value: 'Account',
// },
{
label: 'Item',
value: 'Item',
},
// {
// label: 'Resource',
// value: 'Resource',
// },
// {
// label: 'Value',
// value: 'Value',
// },
// {
// label: 'Charge',
// value: 'Charge',
// },
// {
// label: 'Fixed Asset',
// value: 'Fixed Asset',
// },
],
},
{
name: 'itemId',
displayName: 'Item ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'items',
labelField: 'number',
},
},
{
name: 'sequence',
displayName: 'Sequence Number',
isRequired: false,
type: 'text',
},
{
name: 'lineObjectNumber',
displayName: 'Line Object Number',
description:
'The number of the object (account or item) of the sales invoice line.',
type: 'text',
isRequired: false,
},
{
name: 'description',
displayName: 'Description',
type: 'text',
isRequired: false,
},
{
name: 'unitOfMeasureId',
displayName: 'Unit of Measure ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'unitsOfMeasure',
labelField: 'code',
},
},
{
name: 'unitOfMeasureCode',
displayName: 'Unit of Measure Code',
isRequired: false,
type: 'text',
},
{
name: 'quantity',
displayName: 'Quantity',
isRequired: false,
type: 'number',
},
{
name: 'unitPrice',
displayName: 'Unit Price',
isRequired: false,
type: 'number',
},
{
name: 'discountAmount',
displayName: 'Discount Amount',
type: 'number',
isRequired: false,
},
{
name: 'discountPercent',
displayName: 'Discount Percent',
type: 'number',
isRequired: false,
},
{
name: 'taxCode',
displayName: 'Tax Code',
type: 'text',
isRequired: false,
},
{
name: 'shipmentDate',
displayName: 'Shipment Date',
isRequired: false,
type: 'date',
},
];
export const salesInvoiceLinesEntityNumberProps = [
'quantity',
'unitPrice',
'discountPercent',
'discountAmount',
];

View File

@@ -0,0 +1,198 @@
import { EntityProp } from '../types';
// https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesinvoice
export const salesInvoicesEntityProps: EntityProp[] = [
{
name: 'invoiceDate',
displayName: 'Invoice Date',
type: 'date',
isRequired: false,
},
{
name: 'postingDate',
displayName: 'Posting Date',
type: 'date',
isRequired: false,
},
{
name: 'dueDate',
displayName: 'Due Date',
type: 'date',
isRequired: false,
},
{
name: 'customerId',
displayName: 'Customer ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'customers',
labelField: 'displayName',
},
},
{
name: 'customerNumber',
displayName: 'Customer Number',
type: 'text',
isRequired: false,
},
{
name: 'billToCustomerId',
displayName: 'Bill to Customer ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'customers',
labelField: 'displayName',
},
},
{
name: 'billToCustomerNumber',
displayName: 'Bill to Customer Number',
type: 'text',
isRequired: false,
},
{
name: 'shipToName',
displayName: 'Ship to Name',
type: 'text',
isRequired: false,
},
{
name: 'shipToContact',
displayName: 'Ship to Contact',
type: 'text',
isRequired: false,
},
{
name: 'shipToAddressLine1',
displayName: 'Ship to Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'shipToAddressLine2',
displayName: 'Ship to Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'shipToCity',
displayName: 'Ship to City',
type: 'text',
isRequired: false,
},
{
name: 'shipToCountry',
displayName: 'Ship to Country',
type: 'text',
isRequired: false,
},
{
name: 'shipToState',
displayName: 'Ship to State',
type: 'text',
isRequired: false,
},
{
name: 'shipToPostCode',
displayName: 'Ship to Postalcode',
type: 'text',
isRequired: false,
},
{
name: 'sellToAddressLine1',
displayName: 'Sell to Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'sellToAddressLine2',
displayName: 'Sell to Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'sellToCity',
displayName: 'Sell to City',
type: 'text',
isRequired: false,
},
{
name: 'sellToCountry',
displayName: 'Sell to Country',
type: 'text',
isRequired: false,
},
{
name: 'sellToState',
displayName: 'Sell to State',
type: 'text',
isRequired: false,
},
{
name: 'sellToPostCode',
displayName: 'Sell to Postalcode',
type: 'text',
isRequired: false,
},
{
name: 'currencyId',
displayName: 'Currency ID',
type: 'dynamic_select',
isRequired: false,
options: {
labelField: 'code',
sourceFieldSlug: 'currencies',
},
},
{
name: 'currencyCode',
displayName: 'Currency Code',
type: 'text',
isRequired: false,
},
{
name: 'paymentTermsId',
displayName: 'Payment Terms ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentTerms',
labelField: 'code',
},
},
{
name: 'shipmentMethodId',
displayName: 'Shipment Method ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'shipmentMethods',
labelField: 'code',
},
},
{
name: 'salesperson',
displayName: 'Sales Person Code',
description: 'The salesperson code for the sales invoice.',
isRequired: false,
type: 'text',
},
{
name: 'phoneNumber',
displayName: 'Phone Number',
description: "Specifies the sales invoice's telephone number.",
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
description: "Specifies the sales invoice's email address.",
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,158 @@
import { EntityProp } from '../types';
// https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesorderline
export const salesOrdersLinesEntityProps: EntityProp[] = [
{
name: 'salesOrderId',
displayName: 'Sales Order ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'salesOrders',
labelField: 'number',
},
},
{
name: 'lineType',
displayName: 'Type',
type: 'static_select',
isRequired: false,
options: [
// {
// label: 'Comment',
// value: 'Comment',
// },
// {
// label: 'Account',
// value: 'Account',
// },
{
label: 'Item',
value: 'Item',
},
// {
// label: 'Resource',
// value: 'Resource',
// },
// {
// label: 'Value',
// value: 'Value',
// },
// {
// label: 'Charge',
// value: 'Charge',
// },
// {
// label: 'Fixed Asset',
// value: 'Fixed Asset',
// },
],
},
{
name: 'itemId',
displayName: 'Item ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'items',
labelField: 'number',
},
},
{
name: 'sequence',
displayName: 'Sequence Number',
isRequired: false,
type: 'text',
},
{
name: 'lineObjectNumber',
displayName: 'Line Object Number',
description:
'The number of the object (account or item) of the sales order line.',
type: 'text',
isRequired: false,
},
{
name: 'description',
displayName: 'Description',
type: 'text',
isRequired: false,
},
{
name: 'unitOfMeasureId',
displayName: 'Unit of Measure ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'unitsOfMeasure',
labelField: 'code',
},
},
{
name: 'unitOfMeasureCode',
displayName: 'Unit of Measure Code',
isRequired: false,
type: 'text',
},
{
name: 'quantity',
displayName: 'Quantity',
isRequired: false,
type: 'number',
},
{
name: 'unitPrice',
displayName: 'Unit Price',
isRequired: false,
type: 'number',
},
{
name: 'discountAmount',
displayName: 'Discount Amount',
type: 'number',
isRequired: false,
},
{
name: 'discountPercent',
displayName: 'Discount Percent',
type: 'number',
isRequired: false,
},
{
name: 'taxCode',
displayName: 'Tax Code',
type: 'text',
isRequired: false,
},
{
name: 'shipmentDate',
displayName: 'Shipment Date',
isRequired: false,
type: 'date',
},
{
name: 'invoiceQuantity',
displayName: 'Invoice Quantity',
type: 'number',
isRequired: false,
description:
'The quantity of items from the sales order line to be invoiced.',
},
{
name: 'shipQuantity',
displayName: 'Ship Quantity',
type: 'number',
isRequired: false,
description: 'The quantity of items from the order to be shipped.',
},
];
export const salesOrderLinesEntityNumberProps = [
'quantity',
'unitPrice',
'discountPercent',
'discountAmount',
'invoicedQuantity',
'shipQuantity',
];

View File

@@ -0,0 +1,218 @@
import { EntityProp } from '../types';
export const salesOrdersEntityProps: EntityProp[] = [
{
name: 'orderDate',
displayName: 'Order Date',
type: 'date',
isRequired: false,
},
{
name: 'postingDate',
displayName: 'Posting Date',
type: 'date',
isRequired: false,
},
{
name: 'customerId',
displayName: 'Customer ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'customers',
labelField: 'displayName',
},
},
{
name: 'customerNumber',
displayName: 'Customer Number',
type: 'text',
isRequired: false,
},
{
name: 'billToCustomerId',
displayName: 'Bill to Customer ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'customers',
labelField: 'displayName',
},
},
{
name: 'billToCustomerNumber',
displayName: 'Bill to Customer Number',
type: 'text',
isRequired: false,
},
{
name: 'shipToName',
displayName: 'Ship to Name',
type: 'text',
isRequired: false,
},
{
name: 'shipToContact',
displayName: 'Ship to Contact',
type: 'text',
isRequired: false,
},
{
name: 'shipToAddressLine1',
displayName: 'Ship to Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'shipToAddressLine2',
displayName: 'Ship to Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'shipToCity',
displayName: 'Ship to City',
type: 'text',
isRequired: false,
},
{
name: 'shipToCountry',
displayName: 'Ship to Country',
type: 'text',
isRequired: false,
},
{
name: 'shipToState',
displayName: 'Ship to State',
type: 'text',
isRequired: false,
},
{
name: 'shipToPostCode',
displayName: 'Ship to Postalcode',
type: 'text',
isRequired: false,
},
{
name: 'sellToAddressLine1',
displayName: 'Sell to Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'sellToAddressLine2',
displayName: 'Sell to Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'sellToCity',
displayName: 'Sell to City',
type: 'text',
isRequired: false,
},
{
name: 'sellToCountry',
displayName: 'Sell to Country',
type: 'text',
isRequired: false,
},
{
name: 'sellToState',
displayName: 'Sell to State',
type: 'text',
isRequired: false,
},
{
name: 'sellToPostCode',
displayName: 'Sell to Postalcode',
type: 'text',
isRequired: false,
},
{
name: 'currencyId',
displayName: 'Currency ID',
type: 'dynamic_select',
isRequired: false,
options: {
labelField: 'code',
sourceFieldSlug: 'currencies',
},
},
{
name: 'currencyCode',
displayName: 'Currency Code',
type: 'text',
isRequired: false,
},
{
name: 'pricesIncludeTax',
displayName: 'Prices include Tax?',
isRequired: false,
type: 'boolean',
},
{
name: 'paymentTermsId',
displayName: 'Payment Terms ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentTerms',
labelField: 'code',
},
},
{
name: 'shipmentMethodId',
displayName: 'Shipment Method ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'shipmentMethods',
labelField: 'code',
},
},
{
name: 'salesperson',
displayName: 'Sales Person Code',
description: 'The salesperson code for the sales order.',
isRequired: false,
type: 'text',
},
{
name: 'partialShipping',
displayName:
'Specifies whether partial shipping of items is preferred or not.',
type: 'boolean',
isRequired: false,
},
{
name: 'requestedDeliveryDate',
displayName: 'Requested Delivery Date',
type: 'date',
isRequired: false,
},
{
name: 'phoneNumber',
displayName: 'Phone Number',
description: "Specifies the sales order's telephone number.",
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
description: "Specifies the sales order's email address.",
type: 'text',
isRequired: false,
},
{
name: 'fullyShipped',
displayName: 'Fully Shipped?',
description:
'Specifies whether the items of the sales order were fully shipped or not.',
type: 'boolean',
isRequired: false,
},
];
export const salesOrderLinesEntityNumberProps = ['discountAmount'];

View File

@@ -0,0 +1,134 @@
import { EntityProp } from '../types';
//https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesquoteline
export const salesQuoteLinesEntityProps: EntityProp[] = [
{
name: 'salesQuoteId',
displayName: 'Sales Quote ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'salesQuotes',
labelField: 'number',
},
},
{
name: 'lineType',
displayName: 'Type',
type: 'static_select',
isRequired: false,
options: [
// {
// label: 'Comment',
// value: 'Comment',
// },
// {
// label: 'Account',
// value: 'Account',
// },
{
label: 'Item',
value: 'Item',
},
// {
// label: 'Resource',
// value: 'Resource',
// },
// {
// label: 'Value',
// value: 'Value',
// },
// {
// label: 'Charge',
// value: 'Charge',
// },
// {
// label: 'Fixed Asset',
// value: 'Fixed Asset',
// },
],
},
{
name: 'itemId',
displayName: 'Item ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'items',
labelField: 'number',
},
},
{
name: 'sequence',
displayName: 'Sequence Number',
isRequired: false,
type: 'text',
},
{
name: 'lineObjectNumber',
displayName: 'Line Object Number',
description:
'The number of the object (account or item) of the sales quote line.',
type: 'text',
isRequired: false,
},
{
name: 'description',
displayName: 'Description',
type: 'text',
isRequired: false,
},
{
name: 'unitOfMeasureId',
displayName: 'Unit of Measure ID',
isRequired: false,
type: 'dynamic_select',
options: {
sourceFieldSlug: 'unitsOfMeasure',
labelField: 'code',
},
},
{
name: 'unitOfMeasureCode',
displayName: 'Unit of Measure Code',
isRequired: false,
type: 'text',
},
{
name: 'quantity',
displayName: 'Quantity',
isRequired: false,
type: 'number',
},
{
name: 'unitPrice',
displayName: 'Unit Price',
isRequired: false,
type: 'number',
},
{
name: 'discountAmount',
displayName: 'Discount Amount',
type: 'number',
isRequired: false,
},
{
name: 'discountPercent',
displayName: 'Discount Percent',
type: 'number',
isRequired: false,
},
{
name: 'taxCode',
displayName: 'Tax Code',
type: 'text',
isRequired: false,
},
];
export const salesQuoteLinesEntityNumberProps = [
'quantity',
'unitPrice',
'discountPercent',
'discountAmount',
];

View File

@@ -0,0 +1,203 @@
import { EntityProp } from '../types';
// https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/api/dynamics_salesquote_create
export const salesQuotesEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'documentDate',
displayName: 'Quote Date',
type: 'date',
isRequired: false,
},
{
name: 'postingDate',
displayName: 'Posting Date',
type: 'date',
isRequired: false,
},
{
name: 'customerId',
displayName: 'Customer ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'customers',
labelField: 'displayName',
},
},
{
name: 'customerNumber',
displayName: 'Customer Number',
type: 'text',
isRequired: false,
},
{
name: 'billToCustomerId',
displayName: 'Bill to Customer ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'customers',
labelField: 'displayName',
},
},
{
name: 'billToCustomerNumber',
displayName: 'Bill to Customer Number',
type: 'text',
isRequired: false,
},
{
name: 'shipToName',
displayName: 'Ship to Name',
type: 'text',
isRequired: false,
},
{
name: 'shipToContact',
displayName: 'Ship to Contact',
type: 'text',
isRequired: false,
},
{
name: 'shipToAddressLine1',
displayName: 'Ship to Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'shipToAddressLine2',
displayName: 'Ship to Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'shipToCity',
displayName: 'Ship to City',
type: 'text',
isRequired: false,
},
{
name: 'shipToCountry',
displayName: 'Ship to Country',
type: 'text',
isRequired: false,
},
{
name: 'shipToState',
displayName: 'Ship to State',
type: 'text',
isRequired: false,
},
{
name: 'shipToPostCode',
displayName: 'Ship to Postalcode',
type: 'text',
isRequired: false,
},
{
name: 'sellToAddressLine1',
displayName: 'Sell to Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'sellToAddressLine2',
displayName: 'Sell to Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'sellToCity',
displayName: 'Sell to City',
type: 'text',
isRequired: false,
},
{
name: 'sellToCountry',
displayName: 'Sell to Country',
type: 'text',
isRequired: false,
},
{
name: 'sellToState',
displayName: 'Sell to State',
type: 'text',
isRequired: false,
},
{
name: 'sellToPostCode',
displayName: 'Sell to Postalcode',
type: 'text',
isRequired: false,
},
{
name: 'currencyId',
displayName: 'Currency ID',
type: 'dynamic_select',
isRequired: false,
options: {
labelField: 'code',
sourceFieldSlug: 'currencies',
},
},
{
name: 'currencyCode',
displayName: 'Currency Code',
type: 'text',
isRequired: false,
},
{
name: 'paymentTermsId',
displayName: 'Payment Terms ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentTerms',
labelField: 'code',
},
},
{
name: 'shipmentMethodId',
displayName: 'Shipment Method ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'shipmentMethods',
labelField: 'code',
},
},
{
name: 'salesperson',
displayName: 'Sales Person Code',
description: 'The salesperson code for the sales quote.',
isRequired: false,
type: 'text',
},
{
name: 'phoneNumber',
displayName: 'Phone Number',
description: "Specifies the sales quote's telephone number.",
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
description: "Specifies the sales quote's email address.",
type: 'text',
isRequired: false,
},
{
name: 'validUntilDate',
displayName: 'Valid Until Date',
isRequired: false,
type: 'date',
},
];

View File

@@ -0,0 +1,19 @@
import { EntityProp } from '../types';
export const shipmentMethodsEntityProps: EntityProp[] = [
{
name: 'displayName',
displayName: 'Display Name',
description:
"Specifies the shipment method's name. This name will appear on all sales documents for the shipment method.",
type: 'text',
isRequired: false,
},
{
name: 'code',
displayName: 'Code',
description: 'TThe code of the shipment method.',
type: 'text',
isRequired: false,
},
];

View File

@@ -0,0 +1,112 @@
import { EntityProp } from '../types';
export const vendorsEntityProps: EntityProp[] = [
{
name: 'number',
displayName: 'Number',
type: 'text',
isRequired: false,
},
{
name: 'displayName',
displayName: 'Display Name',
type: 'text',
isRequired: false,
},
{
name: 'addressLine1',
displayName: 'Address Line 1',
type: 'text',
isRequired: false,
},
{
name: 'addressLine2',
displayName: 'Address Line 2',
type: 'text',
isRequired: false,
},
{
name: 'city',
displayName: 'City',
type: 'text',
isRequired: false,
},
{
name: 'state',
displayName: 'State',
type: 'text',
isRequired: false,
},
{
name: 'country',
displayName: 'Country',
type: 'text',
isRequired: false,
},
{
name: 'postalCode',
displayName: 'Postal Code',
type: 'text',
isRequired: false,
},
{
name: 'email',
displayName: 'Email',
type: 'text',
isRequired: false,
},
{
name: 'website',
displayName: 'Website',
type: 'text',
isRequired: false,
},
{
name: 'taxLiable',
displayName: 'Tax Liable?',
type: 'boolean',
isRequired: false,
},
{
name: 'taxRegistrationNumber',
displayName: 'Tax Registration Number',
type: 'text',
isRequired: false,
},
{
name: 'currencyId',
displayName: 'Currency ID',
type: 'dynamic_select',
isRequired: false,
options: {
labelField: 'code',
sourceFieldSlug: 'currencies',
},
},
{
name: 'currencyCode',
displayName: 'Currency Code',
type: 'text',
isRequired: false,
},
{
name: 'paymentTermsId',
displayName: 'Payment Terms ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentTerms',
labelField: 'code',
},
},
{
name: 'paymentMethodId',
displayName: 'Payment Method ID',
type: 'dynamic_select',
isRequired: false,
options: {
sourceFieldSlug: 'paymentMethods',
labelField: 'code',
},
},
];

View File

@@ -0,0 +1,62 @@
interface BaseField {
name: string;
displayName: string;
description?: string;
isRequired: boolean;
}
interface TextField extends BaseField {
type: 'text';
}
interface MultiTextField extends BaseField {
type: 'multi_text';
}
interface NumberField extends BaseField {
type: 'number';
}
interface BooleanField extends BaseField {
type: 'boolean';
}
interface DateField extends BaseField {
type: 'date';
}
interface StaticSelectField extends BaseField {
type: 'static_select';
options: Array<{ label: string; value: string }>;
}
interface StaticMultiSelectField extends BaseField {
type: 'static_multi_select';
options: Array<{ label: string; value: string }>;
}
interface DynamicSingleSelectField extends BaseField {
type: 'dynamic_select';
options: {
sourceFieldSlug: string;
labelField: string;
};
}
interface DynamicMultiSelectField extends BaseField {
type: 'dynamic_multi_select';
options: {
sourceFieldSlug: string;
labelField: string;
};
}
export type EntityProp =
| TextField
| MultiTextField
| NumberField
| BooleanField
| DateField
| StaticMultiSelectField
| StaticSelectField
| DynamicMultiSelectField
| DynamicSingleSelectField;

View File

@@ -0,0 +1,98 @@
import { businessCentralAuth } from '../../';
import {
DedupeStrategy,
Polling,
pollingHelper,
} from '@activepieces/pieces-common';
import {
createTrigger,
AppConnectionValueForAuthProperty,
Property,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { commonProps } from '../common';
import { filterParams, makeClient } from '../common/client';
import dayjs from 'dayjs';
import { TRIGGER_ENTITY_DROPDOWN_OPTIONS } from '../common/constants';
const polling: Polling<
AppConnectionValueForAuthProperty<typeof businessCentralAuth>,
{ company_id: string; record_type: string }
> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
const filter: filterParams = {};
if (lastFetchEpochMS) {
filter['$filter'] = `lastModifiedDateTime gt ${dayjs(
lastFetchEpochMS
).toISOString()}`;
} else {
filter['$top'] = 10;
}
const client = makeClient(auth);
const response = await client.filterRecords(
propsValue.company_id,
propsValue.record_type,
filter
);
return response.value.map((item: any) => {
return {
epochMilliSeconds: dayjs(item['lastModifiedDateTime']).valueOf(),
data: item,
};
});
},
};
export const newOrUpdatedRecordTrigger = createTrigger({
auth: businessCentralAuth,
name: 'new-or-updated-record',
displayName: 'New or Updated Record',
description: 'Triggers when a new record is added or modified.',
type: TriggerStrategy.POLLING,
sampleData: {},
props: {
company_id: commonProps.company_id,
record_type: Property.StaticDropdown({
displayName: 'Record Type',
required: true,
options: {
disabled: false,
options: TRIGGER_ENTITY_DROPDOWN_OPTIONS,
},
}),
},
async test(ctx) {
return await pollingHelper.test(polling, {
auth: ctx.auth,
store: ctx.store,
propsValue: ctx.propsValue,
files: ctx.files,
});
},
async onEnable(ctx) {
await pollingHelper.onEnable(polling, {
auth: ctx.auth,
store: ctx.store,
propsValue: ctx.propsValue,
});
},
async onDisable(ctx) {
await pollingHelper.onDisable(polling, {
auth: ctx.auth,
store: ctx.store,
propsValue: ctx.propsValue,
});
},
async run(ctx) {
return await pollingHelper.poll(polling, {
auth: ctx.auth,
store: ctx.store,
propsValue: ctx.propsValue,
files: ctx.files,
});
},
});