190 lines
8.7 KiB
HTML
190 lines
8.7 KiB
HTML
{% extends 'base.html' %}
|
|
{% load indonesian_filters %}
|
|
|
|
{% block title %}{{ module_title }} - Manufacturing App{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid mt-4">
|
|
<div class="row">
|
|
<div class="col-md-10 offset-md-1">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="mb-0">
|
|
<i class="fas fa-truck-loading"></i> Create Goods Receipt
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Purchase Order Info -->
|
|
<div class="alert alert-info">
|
|
<h6>Creating Goods Receipt for Purchase Order: {{ po.po_number }}</h6>
|
|
<p class="mb-1"><strong>Supplier:</strong> {{ po.supplier.name }}</p>
|
|
<p class="mb-0"><strong>Order Total:</strong> {{ po.total_amount|format_rupiah }}</p>
|
|
</div>
|
|
|
|
<form method="post" id="gr-form">
|
|
{% csrf_token %}
|
|
|
|
<!-- Goods Receipt Header -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="id_receipt_date" class="form-label">Receipt Date *</label>
|
|
<input type="date" name="receipt_date" id="id_receipt_date"
|
|
class="form-control" value="{{ today }}" required>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Order Items for Receipt -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Items to Receive</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if po.items.all %}
|
|
{% for po_item in po.items.all %}
|
|
<div class="row mb-3 p-3 border rounded">
|
|
<div class="col-md-4">
|
|
<h6>{{ po_item.product.name }}</h6>
|
|
<small class="text-muted">{{ po_item.product.code }}</small>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Ordered</label>
|
|
<div class="form-control-plaintext">
|
|
{{ po_item.quantity|indonesian_number:2 }} {{ po_item.product.unit_of_measure.abbreviation }}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Previously Received</label>
|
|
<div class="form-control-plaintext">
|
|
{{ po_item.received_quantity|indonesian_number:2 }} {{ po_item.product.unit_of_measure.abbreviation }}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Receiving Now *</label>
|
|
<input type="text" name="quantity_{{ po_item.id }}"
|
|
class="form-control indonesian-number"
|
|
placeholder="0,00" required
|
|
data-min="0"
|
|
data-max="{{ po_item.quantity|add:po_item.received_quantity|floatformat:2 }}">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Notes</label>
|
|
<input type="text" name="notes_{{ po_item.id }}"
|
|
class="form-control" placeholder="Optional notes">
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No items found in this purchase order.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
<div class="mb-3">
|
|
<label for="id_notes" class="form-label">General Notes</label>
|
|
<textarea name="notes" id="id_notes" class="form-control" rows="3"
|
|
placeholder="Optional general notes for this receipt"></textarea>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{% url 'purchasing:po_detail' po.po_number %}" class="btn btn-secondary">
|
|
<i class="fas fa-times"></i> Cancel
|
|
</a>
|
|
<button type="submit" class="btn btn-success">
|
|
<i class="fas fa-save"></i> Create Goods Receipt
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Indonesian number formatting for quantity fields
|
|
document.querySelectorAll('.indonesian-number').forEach(function(field) {
|
|
field.addEventListener('input', function(e) {
|
|
// Allow only numbers and comma
|
|
let value = this.value.replace(/[^0-9,]/g, '');
|
|
|
|
// Ensure only one comma
|
|
const parts = value.split(',');
|
|
if (parts.length > 2) {
|
|
value = parts[0] + ',' + parts.slice(1).join('');
|
|
}
|
|
|
|
this.value = value;
|
|
});
|
|
|
|
field.addEventListener('blur', function(e) {
|
|
// Format the number properly on blur
|
|
let value = this.value.replace(/[^0-9,]/g, '');
|
|
if (value) {
|
|
const parts = value.split(',');
|
|
if (parts.length === 2) {
|
|
// Ensure decimal part has 2 digits
|
|
parts[1] = parts[1].substring(0, 2).padEnd(2, '0');
|
|
this.value = parts[0] + ',' + parts[1];
|
|
} else {
|
|
this.value = parts[0] + ',00';
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Add validation for quantity fields
|
|
document.querySelectorAll('input[name^="quantity_"]').forEach(function(field) {
|
|
field.addEventListener('blur', function() {
|
|
const value = parseFloat(this.value.replace(',', '.')) || 0;
|
|
const max = parseFloat(this.getAttribute('data-max')) || 0;
|
|
const min = parseFloat(this.getAttribute('data-min')) || 0;
|
|
|
|
if (value < min) {
|
|
this.value = formatIndonesianNumber(min);
|
|
} else if (value > max) {
|
|
this.value = formatIndonesianNumber(max);
|
|
alert('Cannot receive more than ordered quantity!');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Auto-focus on first quantity field
|
|
const firstQuantityField = document.querySelector('input[name^="quantity_"]');
|
|
if (firstQuantityField) {
|
|
firstQuantityField.focus();
|
|
}
|
|
|
|
// Form validation before submission
|
|
document.getElementById('gr-form').addEventListener('submit', function(e) {
|
|
let hasValidQuantity = false;
|
|
document.querySelectorAll('input[name^="quantity_"]').forEach(function(field) {
|
|
const value = parseFloat(field.value.replace(',', '.')) || 0;
|
|
if (value > 0) {
|
|
hasValidQuantity = true;
|
|
}
|
|
});
|
|
|
|
if (!hasValidQuantity) {
|
|
alert('Please enter at least one quantity to receive.');
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
|
|
// Show loading state
|
|
const submitBtn = this.querySelector('button[type="submit"]');
|
|
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Creating...';
|
|
submitBtn.disabled = true;
|
|
});
|
|
});
|
|
|
|
function formatIndonesianNumber(num) {
|
|
return num.toFixed(2).toString().replace('.', ',');
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
{% endblock %} |