fnschool 20251018.81021.825__tar.gz → 20251020.82239.858__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fnschool might be problematic. Click here for more details.

Files changed (117) hide show
  1. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/PKG-INFO +1 -1
  2. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/__init__.py +1 -1
  3. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/forms.py +1 -1
  4. fnschool-20251020.82239.858/src/fnschoo1/canteen/migrations/0017_ingredient_updated_at_alter_category_created_at_and_more.py +30 -0
  5. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/models.py +14 -2
  6. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/consumption/create.html +5 -4
  7. fnschool-20251020.82239.858/src/fnschoo1/canteen/templates/canteen/ingredient/list.html +171 -0
  8. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/views.py +51 -2
  9. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/workbook/generate.py +172 -174
  10. fnschool-20251020.82239.858/src/fnschoo1/fnschool/_settings.py +3 -0
  11. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/settings.py +12 -1
  12. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  13. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/css/fnschool.css +6 -0
  14. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/js/fnschool.js +24 -0
  15. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/PKG-INFO +1 -1
  16. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/SOURCES.txt +2 -0
  17. fnschool-20251018.81021.825/src/fnschoo1/canteen/templates/canteen/ingredient/list.html +0 -139
  18. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/LICENSE +0 -0
  19. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/README.md +0 -0
  20. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/pyproject.toml +0 -0
  21. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/setup.cfg +0 -0
  22. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/__init__.py +0 -0
  23. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/admin.py +0 -0
  24. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/apps.py +0 -0
  25. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0001_initial.py +0 -0
  26. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0002_ingredient_is_disabled.py +0 -0
  27. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0003_consumption_is_disabled_alter_ingredient_is_disabled.py +0 -0
  28. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0004_alter_ingredient_name_category_and_more.py +0 -0
  29. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0005_alter_category_created_at_alter_category_name_and_more.py +0 -0
  30. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0006_category_is_disabled_alter_category_user_and_more.py +0 -0
  31. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0007_alter_consumption_amount_used_and_more.py +0 -0
  32. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0008_category_abbreviation_mealtype.py +0 -0
  33. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0009_alter_category_abbreviation_and_more.py +0 -0
  34. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0010_alter_consumption_options_alter_ingredient_options_and_more.py +0 -0
  35. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0011_category_pin_to_consumptions_top.py +0 -0
  36. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0012_alter_ingredient_storage_date.py +0 -0
  37. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0013_alter_consumption_options_alter_ingredient_options_and_more.py +0 -0
  38. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0014_category_priority.py +0 -0
  39. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0015_alter_category_options_alter_category_priority.py +0 -0
  40. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/0016_consumption_unique_ingredient_date_of_using.py +0 -0
  41. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/migrations/__init__.py +0 -0
  42. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/category/create.html +0 -0
  43. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/category/delete.html +0 -0
  44. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/category/list.html +0 -0
  45. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/category/update.html +0 -0
  46. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/close.html +0 -0
  47. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/consumption/_create.html +0 -0
  48. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/ingredient/close.html +0 -0
  49. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/ingredient/create.html +0 -0
  50. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/ingredient/create_one.html +0 -0
  51. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/ingredient/delete.html +0 -0
  52. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/ingredient/update.html +0 -0
  53. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/meal_type/create.html +0 -0
  54. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/meal_type/delete.html +0 -0
  55. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/meal_type/list.html +0 -0
  56. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/templates/canteen/meal_type/update.html +0 -0
  57. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/tests.py +0 -0
  58. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/urls.py +0 -0
  59. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/canteen/workbook/__init__.py +0 -0
  60. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/__init__.py +0 -0
  61. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/asgi.py +0 -0
  62. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/templatetags/__init__.py +0 -0
  63. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/templatetags/fnschool_tags.py +0 -0
  64. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/urls.py +0 -0
  65. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/views.py +0 -0
  66. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/fnschool/wsgi.py +0 -0
  67. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/locale/en/LC_MESSAGES/django.mo +0 -0
  68. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/manage.py +0 -0
  69. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/__init__.py +0 -0
  70. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/admin.py +0 -0
  71. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/apps.py +0 -0
  72. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/forms.py +0 -0
  73. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/migrations/0001_initial.py +0 -0
  74. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/migrations/0002_alter_profile_bio.py +0 -0
  75. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/migrations/0003_alter_profile_options_alter_profile_address_and_more.py +0 -0
  76. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/migrations/0004_profile_gender.py +0 -0
  77. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/migrations/0005_alter_profile_gender.py +0 -0
  78. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/migrations/__init__.py +0 -0
  79. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/models.py +0 -0
  80. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/signals.py +0 -0
  81. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/templates/profiles/create.html +0 -0
  82. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/templates/profiles/detail.html +0 -0
  83. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/templates/profiles/edit.html +0 -0
  84. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/templates/profiles/log_in.html +0 -0
  85. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/templates/profiles/log_out.html +0 -0
  86. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/tests.py +0 -0
  87. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/urls.py +0 -0
  88. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/profiles/views.py +0 -0
  89. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/css/bootstrap.min.css +0 -0
  90. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/images/favicon.ico +0 -0
  91. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/js/bootstrap.bundle.min.js +0 -0
  92. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/js/bootstrap.min.js +0 -0
  93. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/js/jquery.min.js +0 -0
  94. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/js/jquery.slim.min.js +0 -0
  95. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/static/js/popper.min.js +0 -0
  96. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/base/_content.html +0 -0
  97. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/base/_css.html +0 -0
  98. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/base/_js.html +0 -0
  99. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/base/content.html +0 -0
  100. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/base/header_content_footer.html +0 -0
  101. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/close.html +0 -0
  102. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/home.html +0 -0
  103. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/includes/_footer.html +0 -0
  104. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/includes/_header.html +0 -0
  105. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/includes/_navigation.html +0 -0
  106. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/includes/_paginator.html +0 -0
  107. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/registration/logged_out.html +0 -0
  108. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschoo1/templates/registration/login.html +0 -0
  109. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/SOURCES.txt.py +0 -0
  110. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/dependency_links.txt +0 -0
  111. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/dependency_links.txt.py +0 -0
  112. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/entry_points.txt +0 -0
  113. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/entry_points.txt.py +0 -0
  114. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/requires.txt +0 -0
  115. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/requires.txt.py +0 -0
  116. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/top_level.txt +0 -0
  117. {fnschool-20251018.81021.825 → fnschool-20251020.82239.858}/src/fnschool.egg-info/top_level.txt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fnschool
3
- Version: 20251018.81021.825
3
+ Version: 20251020.82239.858
4
4
  Summary: Just some school related scripts, without any ambition.
5
5
  Author-email: larryw3i <larryw3i@163.com>, Larry Wei <larryw3i@126.com>, Larry W3i <larryw3i@yeah.net>
6
6
  Maintainer-email: larryw3i <larryw3i@163.com>, Larry Wei <larryw3i@126.com>
@@ -6,4 +6,4 @@ import random
6
6
  import sys
7
7
  from pathlib import Path
8
8
 
9
- __version__ = "20251018.81021.825"
9
+ __version__ = "20251020.82239.858"
@@ -20,7 +20,7 @@ class IngredientForm(forms.ModelForm):
20
20
  fields = [
21
21
  f.name
22
22
  for f in Ingredient._meta.fields
23
- if f.name not in ["id", "user"]
23
+ if f.name not in ["id", "user", "updated_at"]
24
24
  ]
25
25
 
26
26
  current_year = date.today().year
@@ -0,0 +1,30 @@
1
+ # Generated by Django 4.2.25 on 2025-10-19 02:03
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("canteen", "0016_consumption_unique_ingredient_date_of_using"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="ingredient",
15
+ name="updated_at",
16
+ field=models.DateTimeField(
17
+ auto_now=True, null=True, verbose_name="Time of updating"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="category",
22
+ name="created_at",
23
+ field=models.DateTimeField(null=True, verbose_name="创建日期"),
24
+ ),
25
+ migrations.AlterField(
26
+ model_name="mealtype",
27
+ name="created_at",
28
+ field=models.DateTimeField(null=True, verbose_name="创建日期"),
29
+ ),
30
+ ]
@@ -21,7 +21,9 @@ class MealType(models.Model):
21
21
  abbreviation = models.CharField(
22
22
  null=True, blank=True, max_length=100, verbose_name=_("Abbreviation")
23
23
  )
24
- created_at = models.DateField(verbose_name=_("Creating Date"))
24
+ created_at = models.DateTimeField(
25
+ null=True, verbose_name=_("Creating Date")
26
+ )
25
27
  is_disabled = models.BooleanField(
26
28
  default=False, verbose_name=_("Is Disabled")
27
29
  )
@@ -41,7 +43,9 @@ class Category(models.Model):
41
43
  abbreviation = models.CharField(
42
44
  null=True, blank=True, max_length=100, verbose_name=_("abbreviation")
43
45
  )
44
- created_at = models.DateField(verbose_name=_("Creating Date"))
46
+ created_at = models.DateTimeField(
47
+ null=True, verbose_name=_("Creating Date")
48
+ )
45
49
  is_disabled = models.BooleanField(
46
50
  default=False, verbose_name=_("Is Disabled")
47
51
  )
@@ -74,6 +78,9 @@ class Ingredient(models.Model):
74
78
  verbose_name=_("User"),
75
79
  )
76
80
  storage_date = models.DateField(verbose_name=_("Storage Date"))
81
+ updated_at = models.DateTimeField(
82
+ null=True, auto_now=True, verbose_name=_("Time of updating")
83
+ )
77
84
  name = models.CharField(max_length=100, verbose_name=_("Ingredient Name"))
78
85
  meal_type = models.ForeignKey(
79
86
  MealType,
@@ -139,6 +146,9 @@ class Ingredient(models.Model):
139
146
  return quantity
140
147
 
141
148
  def get_consuming_quantity(self, date_end):
149
+
150
+ if self.storage_date < date_end:
151
+ return 0
142
152
  consumptions = self.cleaned_consumptions
143
153
  if not consumptions:
144
154
  return 0
@@ -152,6 +162,8 @@ class Ingredient(models.Model):
152
162
  return quantity
153
163
 
154
164
  def get_remaining_quantity(self, date_end):
165
+ if self.storage_date < date_end:
166
+ return 0
155
167
  return self.quantity - self.get_consuming_quantity(date_end)
156
168
 
157
169
  @property
@@ -42,7 +42,7 @@
42
42
  onclick="list_consumptions();">{% trans "Refresh" %}</button>
43
43
  </div>
44
44
  </div>
45
- <div class="table table-responsive table-container">
45
+ <div class="table-responsive table-container">
46
46
  <table class="table table-consumptions cotable-bordered table-striped table-hover table-condensed scroll-vertical ">
47
47
  <thead>
48
48
  <tr>
@@ -97,7 +97,8 @@
97
97
  </table>
98
98
  </div>
99
99
  <div class="">
100
- <button onclick="generate_spreadsheet();"
100
+ <button id="generate_spreadsheet_btn"
101
+ onclick="generate_spreadsheet();"
101
102
  class="btn btn-submit-consumptions btn-success float-end">
102
103
  {% trans "Generate Spreadsheet" %}
103
104
  </button>
@@ -405,11 +406,11 @@
405
406
  }
406
407
 
407
408
  function set_consumptions_table_size() {
408
- const submit_consumptions_btn = $(".btn-submit-consumptions")
409
+ const generate_spreadsheet_btn = $("#generate_spreadsheet_btn")
409
410
  const consumptions_table = $(".table-consumptions")
410
411
  const header = $("header")
411
412
  const footer = $("footer")
412
- const height = Math.round((footer.offset().top - submit_consumptions_btn.height() - consumptions_table.offset().top) * 0.95)
413
+ const height = Math.round((footer.offset().top - generate_spreadsheet_btn.height() - consumptions_table.offset().top) * 0.95)
413
414
  consumptions_table.parent().height(height)
414
415
  }
415
416
  $(window).resize(function() {
@@ -0,0 +1,171 @@
1
+ {% extends "base/header_content_footer.html" %}
2
+ {% load tz %}
3
+ {% load crispy_forms_tags %}
4
+ {% block title %}
5
+ {% trans "Ingredient List" %}
6
+ {% endblock %}
7
+ {% block content %}
8
+ <h1>{% trans "Ingredient List" %}</h1>
9
+ <form method="get"
10
+ action="{% url 'canteen:list_ingredients' %}"
11
+ class="d-flex justify-content-between align-items-center">
12
+ <input type="text"
13
+ name="q"
14
+ onkeydown="if(event.keyCode==13){submit_q();return false;}"
15
+ value="{{ search_query }}"
16
+ placeholder="{% trans 'Search ingredient ...' %}"
17
+ class="form-control" />
18
+ <button type="button"
19
+ onclick="submit_q();"
20
+ class="btn btn-primary text-nowrap">{% trans "Search" %}</button>
21
+ {% if search_query %}
22
+ <a onclick="clear_q();" class="text-nowrap">{% trans "Clear" %}</a>
23
+ {% endif %}
24
+ </form>
25
+ <div class="d-flex justify-content-end pt-2">
26
+ <a class="btn btn-primary mx-1"
27
+ href="{% url "canteen:list_meal_types" %}">{% trans "Ingredient Meal Types" %}</a>
28
+ <a class="btn btn-primary mx-1"
29
+ href="{% url "canteen:list_categories" %}">{% trans "Ingredient Categories" %}</a>
30
+ <a class="btn btn-warning mx-1"
31
+ href="{% url "canteen:create_consumptions" %}">{% trans "Consume" %}</a>
32
+ <a class="btn btn-primary mx-1"
33
+ onclick="open_small_window('{% url 'canteen:create_ingredients' %}')">{% trans "Add via template" %}</a>
34
+ <a class="btn btn-primary"
35
+ onclick="open_small_window('{% url 'canteen:create_ingredient' %}')">{% trans "Add one" %}</a>
36
+ </div>
37
+ <hr />
38
+ <div class="container">
39
+ <div class="table-responsive-lg table-container">
40
+ <table class="table table-bordered table-ingredient table-striped table-hover table-condensed">
41
+ <thead>
42
+ <tr>
43
+ <th scope="col">#</th>
44
+ {% for name,sort, header in headers %}
45
+ <th scope="col"
46
+ data-sort="sort_{{ name }} {{ sort }}"
47
+ onclick="sort_ingredients(this.dataset.sort);">
48
+ {{ header }}
49
+ {% if sort == "+" %}
50
+ &#8593;
51
+ {% elif sort == "-" %}
52
+ &#8595;
53
+ {% endif %}
54
+ </th>
55
+ {% endfor %}
56
+ <th scope="col"></th>
57
+ </tr>
58
+ </thead>
59
+ <tbody>
60
+ {% for ingredient in page_obj %}
61
+ <tr class="tr-ingredient"
62
+ data-ingredient_updated_at="{{ ingredient.updated_at|localtime|date:'Y/m/d H:i:s' }}"
63
+ data-ingredient_storage_date="{{ ingredient.storage_date|localtime|date:'Y/m/d' }}">
64
+ <th scope="row">
65
+ <div class="form-check"
66
+ title="{% trans 'It helps you check the ingredients.' %}">
67
+ <input type="checkbox"
68
+ class="form-check-input"
69
+ id="ingredient_free_nark_{{ ingredient.id }}" />
70
+ <label class="form-check-label"
71
+ for="ingredient_free_nark_{{ ingredient.id }}">
72
+ {{ forloop.counter }}
73
+ </label>
74
+ </div>
75
+ </th>
76
+ <td>{{ ingredient.storage_date }}</td>
77
+ <td>{{ ingredient.name }}</td>
78
+ <td>{{ ingredient.meal_type }}</td>
79
+ <td>{{ ingredient.category }}</td>
80
+ <td>{{ ingredient.quantity }}</td>
81
+ <td>{{ ingredient.quantity_unit_name }}</td>
82
+ <td>{{ ingredient.total_price }}</td>
83
+ <td>
84
+ {% if ingredient.is_ignorable %}
85
+ {% trans "Yes" %}
86
+ {% endif %}
87
+ </td>
88
+ <td>
89
+ {% if ingredient.is_disabled %}
90
+ {% trans "Yes" %}
91
+ {% endif %}
92
+ </td>
93
+ <td class="">
94
+ <a class=""
95
+ target="_blank"
96
+ onclick="open_small_window('{% url 'canteen:edit_ingredient' ingredient.id %}'); return false;">
97
+ {% trans "Edit" %}
98
+ </a>
99
+ |
100
+ <a class="text-danger"
101
+ target="_blank"
102
+ onclick="open_small_window('{% url 'canteen:delete_ingredient' ingredient.id %}'); return false;">
103
+ {% trans "Delete" %}
104
+ </a>
105
+ </td>
106
+ </tr>
107
+ {% empty %}
108
+ {% endfor %}
109
+ </tbody>
110
+ </table>
111
+ </div>
112
+ </div>
113
+ {% include 'includes/_paginator.html' %}
114
+ <script>
115
+ $(document).ready(function() {
116
+ var ingredient_table = $('.table-ingredient')
117
+ var pagination = $('.pagination')
118
+ var footer = $("footer")
119
+ var height = Math.round((footer.offset().top - pagination.height() - ingredient_table.offset().top) * 0.98)
120
+ ingredient_table.parent().height(
121
+ height
122
+ );
123
+ });
124
+ $(document).ready(
125
+ function() {
126
+ make_highlight(".tr-ingredient", "ingredient_updated_at")
127
+ });
128
+
129
+ function clear_q() {
130
+ update_href({
131
+ "q": ""
132
+ })
133
+ }
134
+
135
+ function submit_q() {
136
+ const q_value = document.querySelector('input[name="q"]').value;
137
+ update_href({
138
+ q: q_value
139
+ });
140
+ }
141
+
142
+ function sort_ingredients(value) {
143
+ value = value.trim().split(/\s+/);
144
+ name = value[0];
145
+ value = value[1] || "";
146
+ const url = new URL(window.location.href);
147
+ const params = new URLSearchParams(url.search);
148
+ if (value == "-") {
149
+ value = "";
150
+ } else if (value == "") {
151
+ value = "+";
152
+ } else {
153
+ value = "-";
154
+ }
155
+ i_sort = {};
156
+ i_sort[name] = value;
157
+ update_href(i_sort);
158
+ }
159
+ </script>
160
+ <style>
161
+ .table-container {
162
+ overflow: auto;
163
+ }
164
+
165
+ .table-container thead th {
166
+ position: sticky;
167
+ top: 0;
168
+ }
169
+ </style>
170
+
171
+ {% endblock %}
@@ -395,7 +395,31 @@ def edit_ingredient(request, ingredient_id):
395
395
  ingredient = get_object_or_404(Ingredient, pk=ingredient_id)
396
396
 
397
397
  if request.method == "POST":
398
+
398
399
  form = IngredientForm(request.POST, instance=ingredient)
400
+
401
+ total_price = form.instance.total_price
402
+ quantity = form.instance.quantity
403
+
404
+ [total_price0, quantity0], [total_price1, quantity1] = split_price(
405
+ total_price, quantity
406
+ )
407
+
408
+ if total_price1:
409
+ unit_price_error_msg = _(
410
+ "The unit pricei ({unit_price}) has more than 3 decimal places and cannot be saved. Please modify it again."
411
+ ).format(
412
+ unit_price=(
413
+ Decimal(str(total_price)) / Decimal(str(float(quantity)))
414
+ ).normalize()
415
+ )
416
+ form.add_error("total_price", unit_price_error_msg)
417
+ form.add_error("quantity", unit_price_error_msg)
418
+ return render(
419
+ request, "canteen/ingredient/update.html", {"form": form}
420
+ )
421
+
422
+ form.instance.user = request.user
399
423
  if form.is_valid():
400
424
  form.save()
401
425
  return render(
@@ -413,9 +437,10 @@ def list_ingredients(request):
413
437
  search_query = request.GET.get("q", "")
414
438
  search_query_cp = search_query
415
439
  fields = [
416
- f for f in Ingredient._meta.fields if f.name not in ["id", "user"]
440
+ f
441
+ for f in Ingredient._meta.fields
442
+ if f.name in IngredientForm._meta.fields
417
443
  ]
418
-
419
444
  if search_query:
420
445
  queries = Q(user=request.user)
421
446
 
@@ -846,6 +871,30 @@ class IngredientCreateView(LoginRequiredMixin, CreateView):
846
871
 
847
872
  def form_valid(self, form):
848
873
  form.instance.user = self.request.user
874
+ total_price = form.instance.total_price
875
+ quantity = form.instance.quantity
876
+
877
+ [total_price0, quantity0], [total_price1, quantity1] = split_price(
878
+ total_price, quantity
879
+ )
880
+
881
+ if form.is_valid() and total_price1:
882
+ Ingredient.objects.create(
883
+ user=form.instance.user,
884
+ storage_date=form.instance.storage_date,
885
+ name=form.instance.name + _("(2)"),
886
+ meal_type=form.instance.meal_type,
887
+ category=form.instance.category,
888
+ quantity=quantity1,
889
+ total_price=total_price1,
890
+ quantity_unit_name=form.instance.quantity_unit_name,
891
+ is_ignorable=form.instance.is_ignorable,
892
+ )
893
+ form.instance.name = form.instance.name + _("(1)")
894
+
895
+ form.instance.total_price = total_price0
896
+ form.instance.quantity = quantity0
897
+
849
898
  return super().form_valid(form)
850
899
 
851
900