Add pop-up pricing window for part

- Cost to purchase from suppliers
- Cost to build from BOM
This commit is contained in:
Oliver Walters 2019-05-18 22:58:11 +10:00
parent 54ccf6c7b3
commit dcf79338c1
6 changed files with 132 additions and 2 deletions

View File

@ -138,3 +138,19 @@ class EditBomItemForm(HelperForm):
# Prevent editing of the part associated with this BomItem # Prevent editing of the part associated with this BomItem
widgets = {'part': forms.HiddenInput()} widgets = {'part': forms.HiddenInput()}
class PartPriceForm(forms.Form):
""" Simple form for viewing part pricing information """
quantity = forms.IntegerField(
required=True,
initial=1,
help_text='Input quantity for price calculation'
)
class Meta:
model = Part
fields = [
'quantity'
]

View File

@ -32,10 +32,13 @@
<p><i>{{ part.description }}</i></p> <p><i>{{ part.description }}</i></p>
<p> <p>
<div class='btn-group'> <div class='btn-group'>
{% include "qr_button.html" %}
<button type='button' class='btn btn-default btn-glyph' id='toggle-starred' title='Star this part'> <button type='button' class='btn btn-default btn-glyph' id='toggle-starred' title='Star this part'>
<span id='part-star-icon' class='starred-part glyphicon {% if starred %}glyphicon-star{% else %}glyphicon-star-empty{% endif %}'/> <span id='part-star-icon' class='starred-part glyphicon {% if starred %}glyphicon-star{% else %}glyphicon-star-empty{% endif %}'/>
</button> </button>
{% include "qr_button.html" %}
<button type='button' class='btn btn-default btn-glyph' id='price-button' title='Show pricing information'>
<span id='part-price-icon' class='part-price glyphicon glyphicon-usd'/>
</button>
</div> </div>
</p> </p>
<table class='table table-condensed'> <table class='table table-condensed'>
@ -141,6 +144,15 @@
); );
}); });
$("#price-button").click(function() {
launchModalForm(
"{% url 'part-pricing' part.id %}",
{
submit_text: 'Calculate',
}
);
});
$("#toggle-starred").click(function() { $("#toggle-starred").click(function() {
toggleStar({ toggleStar({
part: {{ part.id }}, part: {{ part.id }},

View File

@ -0,0 +1,41 @@
{% extends "modal_form.html" %}
{% block pre_form_content %}
<div class='alert alert-info alert-block'>
Calculate pricing information for {{ part }}.
</div>
<table class='table table-striped table-condensed'>
<tr>
<td><b>Part</b></td>
<td>{{ part }}</td>
</tr>
<tr>
<td><b>Quantity</b></td>
<td>{{ quantity }}</td>
</tr>
{% if buy_price %}
<tr>
<td><b>Buy Cost</b></td>
<td>{{ buy_price }}</td>
</tr>
{% endif %}
{% if bom_price %}
<tr>
<td><b>BOM Cost</b></td>
<td>{{ bom_price }}</td>
</tr>
{% if part.has_complete_bom_pricing == false %}
<tr>
<td colspan='2'>
<span class='warning-msg'><i>BOM pricing is incomplete</i></span>
</td>
</tr>
{% endif %}
{% endif %}
</table>
<hr>
{% endblock %}

View File

@ -24,6 +24,7 @@ part_detail_urls = [
url(r'^bom-export/?', views.BomDownload.as_view(), name='bom-export'), url(r'^bom-export/?', views.BomDownload.as_view(), name='bom-export'),
url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'), url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'),
url(r'^duplicate/', views.PartDuplicate.as_view(), name='part-duplicate'), url(r'^duplicate/', views.PartDuplicate.as_view(), name='part-duplicate'),
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'),
url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'), url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'),

View File

@ -551,6 +551,62 @@ class PartDelete(AjaxDeleteView):
} }
class PartPricing(AjaxView):
""" View for inspecting part pricing information """
model = Part
ajax_template_name = "part/part_pricing.html"
ajax_form_title = "Part Pricing"
form_class = part_forms.PartPriceForm
def get_part(self):
try:
return Part.objects.get(id=self.kwargs['pk'])
except Part.DoesNotExist:
return None
def get_pricing(self, quantity=1):
part = self.get_part()
ctx = {
'part': part,
'quantity': quantity
}
if part is None:
return ctx
buy_price = part.get_price_info(quantity, bom=False)
bom_price = part.get_price_info(quantity, buy=False)
if buy_price:
ctx['buy_price'] = buy_price
if bom_price:
ctx['bom_price'] = bom_price
return ctx
def get(self, request, *args, **kwargs):
return self.renderJsonResponse(request, self.form_class(), context=self.get_pricing())
def post(self, request, *args, **kwargs):
try:
quantity = int(self.request.POST.get('quantity', 1))
except ValueError:
quantity = 1
# Always mark the form as 'invalid' (the user may wish to keep getting pricing data)
data = {
'form_valid': False,
}
return self.renderJsonResponse(request, self.form_class(), data=data, context=self.get_pricing(quantity))
class CategoryDetail(DetailView): class CategoryDetail(DetailView):
""" Detail view for PartCategory """ """ Detail view for PartCategory """
model = PartCategory model = PartCategory

View File

@ -11,7 +11,11 @@
} }
.starred-part { .starred-part {
color: #ffcc00; color: #ffbb00;
}
.part-price {
color: rgb(13, 245, 25);
} }
/* CSS overrides for treeview */ /* CSS overrides for treeview */