mirror of
https://github.com/inventree/inventree-website.git
synced 2025-06-18 21:15:25 +00:00
deploy: 7a9a696007
This commit is contained in:
@ -25,17 +25,17 @@
|
||||
<meta property="og:title" content="Inventree Supplier Panel" />
|
||||
<meta name="author" content="SergeoLacruz" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta name="description" content="Create Mouser shopping cart from purchase order" />
|
||||
<meta property="og:description" content="Create Mouser shopping cart from purchase order" />
|
||||
<meta name="description" content="The InvenTree-supplier-panel" />
|
||||
<meta property="og:description" content="The InvenTree-supplier-panel" />
|
||||
<link rel="canonical" href="/SergeoLacruz/inventree-supplier-panel" />
|
||||
<meta property="og:url" content="/SergeoLacruz/inventree-supplier-panel" />
|
||||
<meta property="og:site_name" content="InvenTree" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="article:published_time" content="2024-04-22T00:55:04+00:00" />
|
||||
<meta property="article:published_time" content="2024-04-24T21:49:01+00:00" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta property="twitter:title" content="Inventree Supplier Panel" />
|
||||
<script type="application/ld+json">
|
||||
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"SergeoLacruz"},"dateModified":"2024-04-22T00:55:04+00:00","datePublished":"2024-04-22T00:55:04+00:00","description":"Create Mouser shopping cart from purchase order","headline":"Inventree Supplier Panel","mainEntityOfPage":{"@type":"WebPage","@id":"/SergeoLacruz/inventree-supplier-panel"},"url":"/SergeoLacruz/inventree-supplier-panel"}</script>
|
||||
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"SergeoLacruz"},"dateModified":"2024-04-24T21:49:01+00:00","datePublished":"2024-04-24T21:49:01+00:00","description":"The InvenTree-supplier-panel","headline":"Inventree Supplier Panel","mainEntityOfPage":{"@type":"WebPage","@id":"/SergeoLacruz/inventree-supplier-panel"},"url":"/SergeoLacruz/inventree-supplier-panel"}</script>
|
||||
<!-- End Jekyll SEO tag -->
|
||||
|
||||
</head>
|
||||
@ -69,110 +69,268 @@
|
||||
<p> SergeoLacruz</p>
|
||||
</span>
|
||||
</a></span>
|
||||
<span class="sm:ml-2 text-sm">last modified: 22 Apr 2024</span>
|
||||
<span class="sm:ml-2 text-sm">last modified: 24 Apr 2024</span>
|
||||
</h2>
|
||||
|
||||
<div class="flex-wrap md:flex md:flex-nowrap">
|
||||
<div class="w-full md:w-auto md:mr-4">
|
||||
<p>Create Mouser shopping cart from purchase order</p>
|
||||
<h1 id="the-inventree-supplier-panel">The InvenTree-supplier-panel</h1>
|
||||
|
||||
<p>This is a plugin for <a href="https://inventree.org">InvenTree</a>, which translates a purchase order
|
||||
into a Mouser shopping cart. After using this plugin you can directly order the shopping
|
||||
cart on the Mouser WEB page. You need to have a Mouser account and a Mouser API key.
|
||||
The shopping cart will be created in your Mouser account.</p>
|
||||
|
||||
<h2 id="prerequisites">Prerequisites</h2>
|
||||
|
||||
<p>For this plugin to work you need to have Mouser as as supplier in your InvenTree data.
|
||||
Suppliers parts must be added to all the parts that you like to buy at Mouser. All Mouser supplier
|
||||
parts need to have the proper SKU. It needs to match the Mouser part number exactly.</p>
|
||||
|
||||
<p>For access to the Mouser API you need a Mouser account and a shopping cart API key.
|
||||
You can get this on the Mouser WEB page. Do not mess up with the Mouser search API
|
||||
key. This is different. If the key is properly set up you can find it on the Mouser
|
||||
WEB page here:</p>
|
||||
|
||||
<p><img src="/assets/plugins/mouser_api.png" alt="Mouser WEB"></p>
|
||||
<p>This is a plugin for <a href="https://inventree.org">InvenTree</a>, which uploads a purchase order
|
||||
to a supplier WEB page. After using this plugin you can directly order the parts on
|
||||
supplier WEB page. You need to have a supplier account and a different kinds of API keys
|
||||
depending on the supplier.
|
||||
The data will be created in your supplier account. Each time you transfer your PO
|
||||
a new data set cart will be created. So make sure that you delete them from time to time in
|
||||
the supplier WEB interface.
|
||||
The plugin also helps to create supplierparts based on the supplier part number..
|
||||
Actually the plugin supports two suppliers: Mouser and Digikey.</p>
|
||||
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The plugin is on pypi. You can install it by just calling:</p>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install git+https://github.com/SergeoLacruz/inventree-supplier-panel
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install inventree-supplier-panel
|
||||
</code></pre></div></div>
|
||||
|
||||
<h2 id="configuration">Configuration</h2>
|
||||
|
||||
<h3 id="mouser-supplier-id">Mouser Supplier ID</h3>
|
||||
<p>Place here the primary key of the supplier Mouser in your system. You can select from a list of
|
||||
your suppliers.</p>
|
||||
your suppliers. If this is not set the panel will not be displayed and a error is raised.</p>
|
||||
|
||||
<h3 id="supplier-api-key">Supplier API key</h3>
|
||||
<p>Place here you Mouser key for manipulating shopping carts.</p>
|
||||
<h3 id="digikey-supplier-id">Digikey Supplier ID</h3>
|
||||
<p>Place here the primary key of the supplier Digikey in your system. You can select from a list of
|
||||
your suppliers. If this is not set the panel will not be displayed and a error is raised.</p>
|
||||
|
||||
<h3 id="supplier-shopping-cart-key">Supplier shopping cart key</h3>
|
||||
<p>Each shopping cart on the Mouser page has a designated key. You can have several shopping carts
|
||||
in our account. Each cart has a separate key. The plugin puts your PO into the cart with this key.
|
||||
If you do not have a shopping cart key, leave the field empty. The plugin will create a cart
|
||||
and save the key in the field.</p>
|
||||
<h3 id="mouser-api-key">Mouser API key</h3>
|
||||
<p>Place here your Mouser key for manipulating shopping carts. You find it in your Mouser account.</p>
|
||||
|
||||
<h3 id="proxies">Proxies</h3>
|
||||
<h3 id="digikey-id-and-digikey-secret">Digikey ID and Digikey Secret</h3>
|
||||
<p>This is the client ID and the client secret that has been generated in the Digkey API admin WEB portal.
|
||||
Copy it from there to the InvenTree settings.</p>
|
||||
|
||||
<h3 id="digikey-token-and-digikey-refresh-token">Digikey token and Digikey refresh token</h3>
|
||||
<p>These fields are filled automatically. The Digikey API requires two tokens with different life times.
|
||||
Please refer to the Digikey section for more information.</p>
|
||||
|
||||
<h3 id="proxy-con">Proxy CON</h3>
|
||||
<p>Protocol to proxy server e.g. https</p>
|
||||
|
||||
<h3 id="proxy-url">Proxy URL</h3>
|
||||
<p>In case you need to authorise a proxy server between your InvenTree server and the internet
|
||||
put the required setting here. The argument for the request is {‘Proxy CON’ : ‘Proxy URL’} for
|
||||
example:</p>
|
||||
put the required setting here. Example:</p>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ 'https' : 'https://user:password@ipaddress:port' }
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://user:password@ipaddress:port
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>If you do not need this just leave Proxy CON empty.</p>
|
||||
<p>If you do not need this just leave the fields empty.
|
||||
A proxy can also be set using the environment variables PROXY_CON and PROXY_URL. The
|
||||
values in the environment variables overwrite InvenTree settings.</p>
|
||||
|
||||
<h2 id="what-it-does">What it does</h2>
|
||||
<h3 id="base-url">Base URL</h3>
|
||||
<p>The base URL for server instance is in the Server Settings category of InvenTree. The plugin
|
||||
uses this setting to build the OAuth callback for Digikey. Put the correct URL here.</p>
|
||||
|
||||
<p>The plugin creates a new panel which is visible on the purchase order details view.
|
||||
This is called Mouser actions. On the panel there are three things:</p>
|
||||
<h2 id="what-the-plugin-does">What the plugin does</h2>
|
||||
|
||||
<p>The plugin creates a new panel which is visible on the purchase order details view.
|
||||
This is called either Mouser actions or Digikey actions depending on the supplier of the
|
||||
active PO. On the panel there are three things:</p>
|
||||
|
||||
<ul>
|
||||
<li>a button that starts the transfer of your PO to Mouser</li>
|
||||
<li>a button that starts the transfer of your PO to the supplier</li>
|
||||
<li>a status bar that shows error messages</li>
|
||||
<li>a table that contains the created Mouser shopping cart.</li>
|
||||
<li>in case of Digikey a button that initiates the token generation.</li>
|
||||
</ul>
|
||||
|
||||
<p><img src="/assets/plugins/mouser_panel.png" alt="Mouser Panel"></p>
|
||||
|
||||
<p>The button initiates the transfer. It takes each element of your PO, takes the SKU of
|
||||
the Mouser supplier part and adds it into your shopping cart. When finished it downloads
|
||||
the shopping cart from the Mouser WEB page and puts the data into the table. Here you see
|
||||
the actual stock at mouser and an OK bubble when the stock is large enough for you order.
|
||||
You also find the actual price as well as the total amount of your order.</p>
|
||||
<p>The button “Transfer PO” initiates the transfer. It takes each element of your PO using the SKU of
|
||||
the supplier part and transfers it to the suppliers WEB shop. When finished it downloads
|
||||
the data from the WEB page and puts the data into the table. Here you see
|
||||
the actual stock at the supplier and an OK bubble when the stock is large enough for you order.
|
||||
You also find the actual price as well as the total amount of your order. If the supplier
|
||||
detects an error with the part it is displayed in the very right column.</p>
|
||||
|
||||
<p>All items that have been in the cart before get deleted. The cart always contains only the parts
|
||||
in your PO. SergelLacruz</p>
|
||||
|
||||
<p>The plugin also transfers your IPNs (internal part numbers). Mouser reserves a field
|
||||
<p>The plugin also transfers your IPNs (internal part numbers). Most suppliers reserve a field
|
||||
for such numbers. They show up in your shopping cart as well as on the invoice and even
|
||||
on the labels that they put onto the bags and reels.</p>
|
||||
|
||||
<p>Finally the prices that come with the Mouser shopping cart will be copied back into your
|
||||
<p>Finally the actual prices are copied back into your
|
||||
InvenTree purchase order line items. So you can always see what you payed for the part when
|
||||
you ordered it. This does not modify the price breaks of the supplier part. These are stored
|
||||
with the supplier part. Here we just modify the purchase order.</p>
|
||||
|
||||
<p>The panel is only displayed when the supplier of the current purchase order is Mouser.
|
||||
In addition the current user must have change, add or delete access to purchase orders.</p>
|
||||
<h2 id="working-with-mouser">Working with Mouser</h2>
|
||||
|
||||
<h3 id="set-up">Set up</h3>
|
||||
|
||||
<p>For this plugin to work you need to have Mouser as a supplier in your InvenTree database.
|
||||
Supplierparts must be added to all the parts that you like to buy at Mouser. All Mouser supplier
|
||||
parts need to have the proper SKU. It needs to match the Mouser part number exactly.</p>
|
||||
|
||||
<p>For access to the Mouser API you need a Mouser account and a shopping cart API key.
|
||||
You can get this in your Mouser WEB account. Do not mess up with the Mouser search API
|
||||
key. This is a different one. If the key is properly set up you can find it on the Mouser
|
||||
WEB page here:
|
||||
<img src="/assets/plugins/mouser_api.png" alt="Mouser WEB"></p>
|
||||
|
||||
<h3 id="usage">Usage</h3>
|
||||
<p>Using Mouser is easy. Only the Mouser shopping cart key is required for authentication. Its lifetime
|
||||
is endless. Mouser has an API for the shopping cart. On pressing the button a shopping
|
||||
cart is crated and all items are put into this shopping cart. When you login to the
|
||||
Mouser WEB shop you can use this shopping cart for your order.</p>
|
||||
|
||||
<p>Please be aware that the plugin creates a new cart with a new ID each time the button is pressed.
|
||||
If you afterwards create a order in the WEB UI, be careful selecting the right one
|
||||
and delete all unused carts.</p>
|
||||
|
||||
<h4 id="currency-support">Currency support</h4>
|
||||
<p>Mouser needs a country code for currency support. The plugin selects a proper country based on
|
||||
the InvenTree currency setting and transfers this to Mouser. Mouser sends back the sopping cart
|
||||
in the correct currency. The currency name is shown in last line of the table.</p>
|
||||
|
||||
<h2 id="working-with-digikey">Working with Digikey</h2>
|
||||
|
||||
<h3 id="set-up-1">Set up</h3>
|
||||
|
||||
<p>You need a registration on the <a href="https://developer.digikey.com">Digikey API products WEB page</a>.
|
||||
This is not your normal Digikey account for shopping. You have to apply separately. After
|
||||
registration create an organisation and inside the organization a production app.
|
||||
The most important thing to set is the OAuth Callback. This is an URL on your local server
|
||||
that is called by Digikey for key generation. The plugin sets up an URL for this.
|
||||
Just add your local IP. The entry should look somehow like:</p>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://192.168.1.40:8123/plugin/suppliercart/digikeytoken/
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>In this example 192.168.1.40:8123 is the local IP address and port where my
|
||||
InvenTree development server runs. Place here the appropriate address.
|
||||
In Production products section make sure that Product information and MyLists is activated.</p>
|
||||
|
||||
<p>In the View tab of your app you find the Client-ID and the Client-Secret. Place those in
|
||||
the plugin settings.</p>
|
||||
|
||||
<p>Digikey Supplierparts have to by in your InvenTree Database as described already in
|
||||
the Mouser section.</p>
|
||||
|
||||
<h3 id="usage-1">Usage</h3>
|
||||
<p>Using Digikey is more complex. The authorisation system is token based and they do not
|
||||
have a shopping cart API.</p>
|
||||
|
||||
<h4 id="authorization">Authorization</h4>
|
||||
<p>The Digikey Client ID and the Client secret are the first things you need. With those
|
||||
you call an API endpoint. You HAVE to go through an interactive browser window and
|
||||
enter your credentials. Afterwards Digikey opens a callback URL on your local machine
|
||||
and transfers a key. With this key the plugin calls another API endpoint to create
|
||||
a token and a refresh token. The key gets bad after 60 seconds.</p>
|
||||
|
||||
<p>The token is used for each call to a Digikey API. It is good for 30 minutes. It has to
|
||||
be refreshed using the refresh token. This one is valid for 90 days.</p>
|
||||
|
||||
<p>The plugin has a button in the panel that initiates the first step. It opens a browser
|
||||
where you enter your credentials. When the OAuth callback is properly set the URL
|
||||
…plugin/suppliercart/digikeytoken/ is called. This triggers a call to
|
||||
https://api.digikey.com/v1/oauth2/token from where the plugin get the tokens. The tokens
|
||||
are stored in the plugin setting area. Do not change them manually.</p>
|
||||
|
||||
<p>Each time you transfer a PO the refresh token is called independently from the
|
||||
tokens live time. This also refreshes the refresh token. So you are save when
|
||||
you use the plugin ate least once in 90 days. In case the token gets bad you need to
|
||||
create a fresh set using the token button again.</p>
|
||||
|
||||
<p>If you are confused now read the documentation on the Digikey WEB page for more details.</p>
|
||||
|
||||
<h4 id="mylists">MyLists</h4>
|
||||
<p>Digikey does not have such a simple shopping cart API. The plugin uses the MyLists API.
|
||||
It creates a list on the WEB shop that can easily be transferred to a shopping
|
||||
cart. When creating a list a list name has to be provided. The plugin creates a name
|
||||
based on the PO name and adding a -xx that counts upwards each time you push the button.
|
||||
The reason is that each name is allowed only once. Even when the list is deleted, the
|
||||
name stays blocked forever. If you are done with your order delete the lists from your
|
||||
Digikey WEB account.</p>
|
||||
|
||||
<h4 id="currency-support-1">Currency support</h4>
|
||||
<p>Digikey requires a country code and a currency code. The plugin uses the same translation
|
||||
as mentioned in the Mouser section and transfers both to Digikey. Digikey sends back the
|
||||
list in the correct currency. Unfortunately the currency code is not sent back. The only
|
||||
thing Digikey sends is a currency symbol but no info if $ is USD, AUD or whatever kind of Dollar.
|
||||
The plugin shows the symbol in the table for control.</p>
|
||||
|
||||
<h2 id="automatically-add-supplierparts">Automatically add supplierparts</h2>
|
||||
<p>The plugin can add supplierparts based on the supplier part number. For users with
|
||||
edit part permission a panel called “Automatic Supplier parts” is shown. Here
|
||||
you can select the supplier and add the exact supplier part number. The plugin
|
||||
will create a corresponding supplierpart. I can fill the following part fields automatically:</p>
|
||||
|
||||
<ul>
|
||||
<li>Supplier part number</li>
|
||||
<li>URL</li>
|
||||
<li>Package when available</li>
|
||||
<li>Lifecycle status</li>
|
||||
<li>Minimum order</li>
|
||||
<li>Description</li>
|
||||
</ul>
|
||||
|
||||
<p>If the supplier does not provide information for a field it it left empty.</p>
|
||||
|
||||
<h2 id="how-it-works">How it works</h2>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def get_custom_panels(self, view, request)
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>This defines the panel. The function must return a panels list. Here it returns just one
|
||||
panel. The panel is returned under three conditions: The view must be PurchaseOrderDetail,
|
||||
the supplier must be Mouser or Digikey and the user must have edit permissions to purchase orders.
|
||||
The content_template is an html file that defines how the panel content looks.</p>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>re_path(r'transfercart/(?P<pk>\d+)/', self.TransferCart, name='transfer-cart'),
|
||||
</code></pre></div></div>
|
||||
<p>Here we define the url that controls the panel. Let’s look at the details here:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><code class="language-plaintext highlighter-rouge">name='transfer-cart'</code>: This is the name under which the url is called from the html file. We will
|
||||
come to that later when we discuss the template.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code class="language-plaintext highlighter-rouge">self.TransferCart</code> is the function that is called. It is defined later in this plugin</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code class="language-plaintext highlighter-rouge">transfercart/(?P<pk>\d+)/</code> The string that looks a bit like white noise defines the url. transfercart
|
||||
is the url which can be chosen freely. The ? is well known for parameters. In this case we get just one
|
||||
parameter, the orders primary key. \d+ is a regular expression that limits the parameters to a digital
|
||||
number with n digits.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>May be it is worth to leave a few more words on this. We define the url of the plugin. This is called by the Javascript
|
||||
function when we push the button. Let’s have a look on the names and how they belong together:</p>
|
||||
|
||||
<p><img src="/assets/plugins/plugin_dataflow.svg" alt="Dataflow"></p>
|
||||
|
||||
<p>In the picture you see the relevant lines in the python and java code. The names in the coloured boxes need to match.
|
||||
In case something does not fit the panel will not render and you will get an error message.</p>
|
||||
|
||||
<h2 id="issues">Issues</h2>
|
||||
<h3 id="mouser-messed-up">Mouser messed up</h3>
|
||||
<p>It can happen that the Mouser shopping cart API gets messed up and no item are added into
|
||||
your cart. Just delete the cart in that case and delete the key in the plugin setting.
|
||||
A new key will be created and usually works.</p>
|
||||
|
||||
<h3 id="api-keys-are-global">API keys are global</h3>
|
||||
<p>The API keys and especially the proxy password are user specific and shall not be given to
|
||||
<p>The API keys and especially the proxy password are user specific and shall not be given to
|
||||
others. Up to now there are no user specific settings in InvenTree. So these keys are global
|
||||
and visible to, at least every admin. All users who use the plugin will have the same
|
||||
keys. We use a team key to solve this.</p>
|
||||
|
||||
<h3 id="other-suppliers">Other suppliers</h3>
|
||||
<p>Actually this works only for Mouser. Other suppliers like Digikey, Farnell or Buerklin
|
||||
might follow.</p>
|
||||
<h3 id="missing-digikey-features">Missing DigiKey features</h3>
|
||||
<p>Digikey allows more features like customer ID and list owners. These are not implemented so far.
|
||||
The plugin supports just a single Digikey organization and user. Some APIs require a createdBy
|
||||
value to be set. xxxx works fine so far.</p>
|
||||
|
||||
<h3 id="https-callback">https Callback</h3>
|
||||
<p>The OAuto callback setting in your Digikey WEB account allows only https. http is not allowed.
|
||||
This is usually not a problem in production environments. However the development server
|
||||
usually runs http. But InvenTree has the required stuff for https on board. I just changed
|
||||
the runserver to runsslserver in tasks.py.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@ -202,7 +360,7 @@ might follow.</p>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Package on PyPI:<pre class="my-0">inventree-supplier-panel</pre>
|
||||
|
||||
|
||||
|
||||
@ -245,6 +403,8 @@ might follow.</p>
|
||||
|
||||
<a href="/plugins/tags/#mouser"><span class="plugin_tag">mouser</span></a>
|
||||
|
||||
<a href="/plugins/tags/#digikey"><span class="plugin_tag">digikey</span></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,11 +31,11 @@
|
||||
<meta property="og:url" content="/SergeoLacruz/inventree-zebra-plugin" />
|
||||
<meta property="og:site_name" content="InvenTree" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="article:published_time" content="2024-04-22T00:55:04+00:00" />
|
||||
<meta property="article:published_time" content="2024-04-24T21:49:01+00:00" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta property="twitter:title" content="Inventree Zebra Plugin" />
|
||||
<script type="application/ld+json">
|
||||
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"SergeoLacruz"},"dateModified":"2024-04-22T00:55:04+00:00","datePublished":"2024-04-22T00:55:04+00:00","description":"Zebra Label Printer Plugin for Inventree","headline":"Inventree Zebra Plugin","mainEntityOfPage":{"@type":"WebPage","@id":"/SergeoLacruz/inventree-zebra-plugin"},"url":"/SergeoLacruz/inventree-zebra-plugin"}</script>
|
||||
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"SergeoLacruz"},"dateModified":"2024-04-24T21:49:01+00:00","datePublished":"2024-04-24T21:49:01+00:00","description":"Zebra Label Printer Plugin for Inventree","headline":"Inventree Zebra Plugin","mainEntityOfPage":{"@type":"WebPage","@id":"/SergeoLacruz/inventree-zebra-plugin"},"url":"/SergeoLacruz/inventree-zebra-plugin"}</script>
|
||||
<!-- End Jekyll SEO tag -->
|
||||
|
||||
</head>
|
||||
@ -69,19 +69,21 @@
|
||||
<p> SergeoLacruz</p>
|
||||
</span>
|
||||
</a></span>
|
||||
<span class="sm:ml-2 text-sm">last modified: 22 Apr 2024</span>
|
||||
<span class="sm:ml-2 text-sm">last modified: 24 Apr 2024</span>
|
||||
</h2>
|
||||
|
||||
<div class="flex-wrap md:flex md:flex-nowrap">
|
||||
<div class="w-full md:w-auto md:mr-4">
|
||||
<p>Zebra Label Printer Plugin for Inventree</p>
|
||||
|
||||
<p>This is a label printing plugin for <a href="https://inventree.org">InvenTree</a>, which provides support for Zebra Label printers .
|
||||
It was only tested with GK420T but should work for other ZPL printers too. It uses the ZPL library to
|
||||
convert the png data provided by InvenTree to Zebra’s bitmap format.</p>
|
||||
<p>This is a label printing plugin for <a href="https://inventree.org">InvenTree</a>, which provides
|
||||
support for Zebra Label printers. It was only tested with GK420T but should work for
|
||||
other ZPL printers too. It uses the ZPL library to convert the png data provided by
|
||||
InvenTree to Zebra’s bitmap format.</p>
|
||||
|
||||
<p>It can output the print data either to a local printer connected to the computer via USB or to a network printer
|
||||
with an IP address. The output can be configured in the InvenTree plugin user interface.</p>
|
||||
<p>It can output the print data either to a local printer connected to the computer via
|
||||
USB or to a network printer with an IP address. The output can be configured in the
|
||||
InvenTree plugin user interface.</p>
|
||||
|
||||
<p>Error handling is very basic.</p>
|
||||
|
||||
@ -107,12 +109,12 @@ with an IP address. The output can be configured in the InvenTree plugin user in
|
||||
device /dev/usb/lp0. No printer spooler is involved so far.</p>
|
||||
|
||||
<h3 id="threshold">Threshold</h3>
|
||||
<p>The image from pillow comes in greyscale. The plugin converts it ti pure BW because this gives a much
|
||||
<p>The image from pillow comes in greyscale. The plugin converts it ti pure BW because this gives a much
|
||||
better print result. The threshold between black and white can be adjusted here.</p>
|
||||
|
||||
<h3 id="darkness">Darkness</h3>
|
||||
<p>This is a value that influences the darkness of the print. Allowed values are 0 (white) to 30 (black).
|
||||
It is directly converted to a SD command in ZPL. If your black areas tend to blur out reduce the
|
||||
It is directly converted to a SD command in ZPL. If your black areas tend to blur out reduce the
|
||||
darkness.</p>
|
||||
|
||||
<h3 id="dots-per-mm">Dots per mm</h3>
|
||||
@ -132,8 +134,8 @@ is passed directly to the printer without any checks. So be careful when editing
|
||||
here.</p>
|
||||
|
||||
<h2 id="label-template">Label Template</h2>
|
||||
<p>The label needs a template described in html and css. The template should start with a page definition
|
||||
that defines the label size as shown below:</p>
|
||||
<p>The label needs a template described in html and css. The template should
|
||||
start with a page definition that defines the label size as shown below:</p>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> @page {
|
||||
{% localize off %}
|
||||
@ -146,13 +148,32 @@ that defines the label size as shown below:</p>
|
||||
}
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>The height and width parameters are defined in the InvenTree admin panel in the label section. These values
|
||||
have to fit the label size that is in the printer. See the example templates for details on template definition.</p>
|
||||
<p>The height and width parameters are defined in the InvenTree admin panel
|
||||
in the label section. These values have to fit the label size that is in
|
||||
the printer. See the example templates for details on template definition.</p>
|
||||
|
||||
<h2 id="multi-printer-hack">Multi printer hack</h2>
|
||||
<p>We have the requirement to print labels in different sizes. As we do not
|
||||
want to change the reel for each print we set up a second printer loaded
|
||||
with a different label size. InvenTree is not yet able to handle different
|
||||
printers. So I added a multi printer hack. You can define a key with an IP
|
||||
address in the label meta data:</p>
|
||||
|
||||
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{"ip_address":"xxx.yyy.zzz.eee"}
|
||||
{"darkness":xx}
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>If the printer driver finds that key, the IP address from the printer settings
|
||||
is overwritten with the address from the meta data. So the print will end up
|
||||
in another printer.</p>
|
||||
|
||||
<p>Only the IP address and darkness can be overwritten so far. All other settings remain.</p>
|
||||
|
||||
<h2 id="how-it-works">How it works</h2>
|
||||
<p>First import all the stuff you need. Here we use the translation mechanism from Django for multi language support.
|
||||
The import the InvenTree libs and everything you need for plugin. Here we have ZPL for the Zebra bitmaps and socket
|
||||
for the IP connection to the printer.</p>
|
||||
<p>First import all the stuff you need. Here we use the translation mechanism from
|
||||
Django for multi language support. The import the InvenTree libs and everything
|
||||
you need for plugin. Here we have ZPL for the Zebra bitmaps and socket for the
|
||||
IP connection to the printer.</p>
|
||||
|
||||
<p>The next part is this:</p>
|
||||
|
||||
@ -167,7 +188,7 @@ for the IP connection to the printer.</p>
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>The name of the class can be freely chosen. You reference to it in the entry_points section of the setup.py file.
|
||||
The parameters need to be like in the example. Then there is the description block. The keywords are fixed and
|
||||
The parameters need to be like in the example. Then there is the description block. The keywords are fixed and
|
||||
need to be like that. The values are found in the UI as shown in the pictures below.</p>
|
||||
|
||||
<p><img src="/assets/plugins/plugin_admin.png" alt="Admin">
|
||||
@ -191,9 +212,9 @@ need to be like that. The values are found in the UI as shown in the pictures be
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>We need to define a dict with the name SETTINGS. Please be aware the keys need to be in all CAPITAL letters like CONNECTION.
|
||||
Simple parameters are just text strings like the port. We can set a default. The name and description shows up in the UI.
|
||||
Simple parameters are just text strings like the port. We can set a default. The name and description shows up in the UI.
|
||||
Instead of a simple text we can also use choices. The first string like “local” it the key you use in the code. The second
|
||||
one is the description in the UI.
|
||||
one is the description in the UI.
|
||||
After that we need to define a function:</p>
|
||||
|
||||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">print_label</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">){</span>
|
||||
@ -212,27 +233,27 @@ After that we need to define a function:</p>
|
||||
<li>png_file</li>
|
||||
</ul>
|
||||
|
||||
<p>The item_instance is the part to be printed. This allows direct access to all part data. The arguments width and height
|
||||
come from the settings of the label in the admin interface. NOT from the html template.
|
||||
For the Zebra printer we use the png_file. This is a PIL (python Pillow) object with the graphic of the label in PNG format.
|
||||
<p>The item_instance is the part to be printed. This allows direct access to all part data. The arguments width and height
|
||||
come from the settings of the label in the admin interface. NOT from the html template.
|
||||
For the Zebra printer we use the png_file. This is a PIL (python Pillow) object with the graphic of the label in PNG format.
|
||||
The PIL object is a greyscale image. Because the printer can just print pure BW we convert this to a BW picture.</p>
|
||||
|
||||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fn</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span> <span class="p">:</span> <span class="mi">255</span> <span class="k">if</span> <span class="n">x</span> <span class="o">></span> <span class="n">Threshold</span> <span class="k">else</span> <span class="mi">0</span>
|
||||
<span class="n">label_image</span> <span class="o">=</span> <span class="n">label_image</span><span class="p">.</span><span class="nf">convert</span><span class="p">(</span><span class="sh">'</span><span class="s">L</span><span class="sh">'</span><span class="p">).</span><span class="nf">point</span><span class="p">(</span><span class="n">fn</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="sh">'</span><span class="s">1</span><span class="sh">'</span><span class="p">)</span>
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>The threshold can by modified by a plugin parameter. 200 is a good starting value. This trick gives much better prints.
|
||||
<p>The threshold can by modified by a plugin parameter. 200 is a good starting value. This trick gives much better prints.
|
||||
We can put the result of this directly into the ZPL library.</p>
|
||||
|
||||
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">l</span> <span class="o">=</span> <span class="n">zpl</span><span class="p">.</span><span class="nc">Label</span><span class="p">(</span><span class="n">Height</span><span class="p">,</span> <span class="n">Width</span><span class="p">,</span> <span class="n">dpmm</span><span class="p">)</span>
|
||||
<span class="n">l</span><span class="p">.</span><span class="nf">origin</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">li</span><span class="p">.</span><span class="nf">set_darkness</span><span class="p">(</span><span class="n">darkness</span><span class="p">)</span>
|
||||
<span class="bp">...</span>
|
||||
<span class="n">l</span><span class="p">.</span><span class="nf">write_graphic</span><span class="p">(</span><span class="n">label_image</span><span class="p">,</span> <span class="n">Width</span><span class="p">)</span>
|
||||
<span class="n">l</span><span class="p">.</span><span class="nf">endorigin</span><span class="p">()</span>
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>Width and Height define is the size of the label in millimeters as described above.
|
||||
The third parameter is the resolution of the printer in dots per mm.
|
||||
The third parameter is the resolution of the printer in dots per mm.
|
||||
write_graphic converts the pillow data to ZPL.</p>
|
||||
|
||||
<p>The plugin was tested with a labels of various sizes defined using css and html. The DPI scaling
|
||||
@ -248,11 +269,11 @@ Let’s have a look at the following printout:</p>
|
||||
|
||||
<p><img src="/assets/plugins/qr.png" alt="QRCodes"></p>
|
||||
|
||||
<p>Both codes have been printed with the same printer on the same reel. The left one is
|
||||
<p>Both codes have been printed with the same printer on the same reel. The left one is
|
||||
hardly readable using my mobile. The right one reads easily even as it is smaller.</p>
|
||||
|
||||
<h3 id="secret-1-scale">Secret 1, Scale</h3>
|
||||
<p>The printer resolution is 8 dots per mm resulting in a dot size of 0.125mm. The QR code pixel
|
||||
<p>The printer resolution is 8 dots per mm resulting in a dot size of 0.125mm. The QR code pixel
|
||||
and the printer pixel size should be integrally divisible. The code in the picture has 21
|
||||
pixels plus one in the frame, so 23 pixel. The frame is set in the HTML description.</p>
|
||||
|
||||
@ -260,7 +281,7 @@ pixels plus one in the frame, so 23 pixel. The frame is set in the HTML descript
|
||||
</code></pre></div></div>
|
||||
|
||||
<p>I selected two dots per pixel. So 23 * 2 * 0.125 = 6.125mm. If the size is something different
|
||||
scaling takes place and the result might be worse. If you like a larger printout select more
|
||||
scaling takes place and the result might be worse. If you like a larger printout select more
|
||||
dots per pixel. From a certain size upwards the value does not matter any more because the code
|
||||
gets large enough to be readable in any quality.</p>
|
||||
|
||||
@ -273,9 +294,9 @@ media type and printer age. The printer head tends to wear out and the darkness
|
||||
need an adjustment from time to time.</p>
|
||||
|
||||
<h3 id="alternative">Alternative</h3>
|
||||
<p>You can also bypass the InvenTree template and printing system and directly create ZPL from
|
||||
<p>You can also bypass the InvenTree template and printing system and directly create ZPL from
|
||||
the parts data. The printer knows best how to render the label and the print quality is best.
|
||||
If you are interested in this way have a look at the <a href="https://github.com/yellowcrescent/inventree-zpl-plugin">inventree-zpl-plugin</a>
|
||||
If you are interested in this way have a look at the <a href="https://github.com/yellowcrescent/inventree-zpl-plugin">inventree-zpl-plugin</a>
|
||||
that does exactly that.</p>
|
||||
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user