# bill of materials

{% file src="<https://664948176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdX27l90MHtjXhtBupXys%2Fuploads%2F9SfxY9mUsUkwOkVHbwWa%2Flibrary.zip?alt=media&token=3831def0-6a87-4349-ab15-13747578815e>" %}

add delete button<br>

{% file src="<https://664948176-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdX27l90MHtjXhtBupXys%2Fuploads%2FB7J6KnBHWm58xaCRq0Ld%2Flibrary.zip?alt=media&token=4c358c9a-34c9-4240-b220-535b6af3985d>" %}

<https://chat.openai.com/share/99cb92bf-404a-42f2-8346-fc87a89a4bba>

**settings.py**

```python
STATIC_URL = 'static/'
STATICFILES_DIRS = [
    BASE_DIR / 'static',
]
STATIC_ROOT=(BASE_DIR/ "assets/")

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'assets/media/')
```

**models.py**

```python
class BillOfMaterials(models.Model):
    code = models.CharField(max_length=20)
    name = models.CharField(max_length=100)
    bomtype = models.CharField(max_length=20)
    quantity = models.DecimalField(max_digits=10, decimal_places=4)

class ChildComponent(models.Model):
    bill_of_materials = models.ForeignKey(BillOfMaterials, on_delete=models.CASCADE, related_name='child_components')
    code = models.CharField(max_length=20)
    name = models.CharField(max_length=100)
    uom = models.CharField(max_length=20)
    quantity = models.DecimalField(max_digits=10, decimal_places=4)


class Production(models.Model):
    name = models.CharField(max_length=100)
    quantity = models.DecimalField(max_digits=10, decimal_places=4)

    def __str__(self):
        return self.name

class ProductionComponent(models.Model):
    production = models.ForeignKey(Production, on_delete=models.CASCADE, related_name='production_components')
    code = models.CharField(max_length=20)
    name = models.CharField(max_length=100)
    uom = models.CharField(max_length=20)
    quantity = models.DecimalField(max_digits=10, decimal_places=4)

    def __str__(self):
        return self.name


```

**admin.py**

```python
from django.contrib import admin
from django.forms import inlineformset_factory
from .models import (
    BillOfMaterials,
    ChildComponent,
    Production, 
    ProductionComponent
)

# Bill Of Materials 
class ChildComponentInline(admin.TabularInline):
    model = ChildComponent
class BillOfMaterialsAdmin(admin.ModelAdmin):
    inlines = [ChildComponentInline]
admin.site.register(BillOfMaterials, BillOfMaterialsAdmin)


# Production Order
class ProductionComponentInline(admin.TabularInline):
    model = ProductionComponent
class ProductionAdmin(admin.ModelAdmin):
    inlines = [ProductionComponentInline]
    class Media:
        js = ('js/fetch_sales_order_info.js',)
        defer = True  # Add the defer attribute
admin.site.register(Production, ProductionAdmin)
```

### create static/js  folder and store **fetch\_sales\_order\_info.js**

```javascript
(function ($) {
    $(document).ready(function(){
        $('#id_name, #id_quantity').on('change',function(){
            var initialname = $('#id_name').val();
            var initialquantity = $('#id_quantity').val();
            if (initialname.trim() !== '' && initialquantity.trim() !== '') {
                $.ajax({
                    type: 'POST',
                    url: '/library/ajax/',
                    data: {
                        'name': initialname,
                        'quantity': initialquantity
                    },
                    dataType: 'json',
                    success: function(response){
                        updateFormset(response);
                        // $('#id_production_components-0-quantity').val(response.quantity);

                    }
                });
            }

        });
function updateFormset(data) {
  var formsetTable = $('table');
  formsetTable.empty();
    // Add table header
    var tableHeader = $('<thead>').appendTo(formsetTable);
    var headerRow = $('<tr>').appendTo(tableHeader);
    $('<th>').addClass('column-code required').text('Code').appendTo(headerRow);
    $('<th>').addClass('column-name required').text('Name').appendTo(headerRow);
    $('<th>').addClass('column-uom required').text('Uom').appendTo(headerRow);
    $('<th>').addClass('column-quantity required').text('Quantity').appendTo(headerRow);
    $('<th>').text('Delete?').appendTo(headerRow);
  
    // Add table body
    var tableBody = $('<tbody>').appendTo(formsetTable);
  data.forEach(function (component, index) {
    var row = $('<tr>');
    var codeCell = $('<td>');
    var codeInput = $('<input type="text" maxlength="20" class="vTextField">');
    codeInput.attr('name', 'production_components-' + index + '-code');
    codeInput.val(component.code);
    codeCell.append(codeInput);
    var nameCell = $('<td>');
    var nameInput = $('<input type="text" maxlength="100" class="vTextField">');
    nameInput.attr('name', 'production_components-' + index + '-name');
    nameInput.val(component.name);
    nameCell.append(nameInput);
    var uomCell = $('<td>');
    var uomInput = $('<input type="text" maxlength="20" class="vTextField">');
    uomInput.attr('name', 'production_components-' + index + '-uom');
    uomInput.val(component.uom);
    uomCell.append(uomInput);
    var quantityCell = $('<td>');
    var quantityInput = $('<input type="number" min="0" step="0.0001" required>');
    quantityInput.attr('name', 'production_components-' + index + '-quantity');
    quantityInput.val(component.quantity);
    quantityCell.append(quantityInput);

    var deleteCell = $('<td>');
    var deleteButton = $('<button>').text('Delete');
    deleteButton.addClass('delete-button');
    deleteButton.on('click', function() {
      // Handle delete button click
      row.remove();
    });
    deleteCell.append(deleteButton);   


    
    row.append(codeCell, nameCell, uomCell, quantityCell,deleteCell);
    formsetTable.append(row);
  });
  
}

          
          
    });
})(jQuery);


```

**views.py**

```python
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import BillOfMaterials
@csrf_exempt
def ajax_view(request):
    if request.method == 'POST':
        production_name  = request.POST.get('name')
        production_quantity  = request.POST.get('quantity')
        bill_of_materials = BillOfMaterials.objects.filter(name=production_name).first()
        if bill_of_materials:
            child_components = bill_of_materials.child_components.all()
            updated_components = []



            for component in child_components:
                if bill_of_materials.quantity == production_quantity:
                    updated_quantity = float(component.quantity)
                else:
                    updated_quantity = float(component.quantity) * (float(production_quantity) / float(bill_of_materials.quantity))
                updated_quantity = format(updated_quantity, '.4f')
                updated_components.append({
                    'id': component.id,
                    'code': component.code,
                    'name': component.name,
                    'uom': component.uom,
                    'quantity': updated_quantity
                })
                    

        return JsonResponse(updated_components, safe=False)

    return JsonResponse([], safe=False)
```

**urls.py**

```python
from django.urls import path
from .views import ajax_view

urlpatterns = [

    path('ajax/', ajax_view, name='ajax_view'),

]
```

<br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://olee-tech.gitbook.io/django/undefined-5/bill-of-materials.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
