Merge commit '47c6906a74f41eed5b56f4dc43ea0d4e20415237' into block-notes

This commit is contained in:
Oliver Walters
2026-06-02 07:33:29 +00:00
85 changed files with 31217 additions and 28215 deletions
+1
View File
@@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Removed ### Removed
- [#12071](https://github.com/inventree/InvenTree/pull/12071) removes the "review_needed" field on the StockItem model. Note that this field was never exposed to the API or any business logic, and is essentially a no-op field which is not used for anything. This field was removed to simplify the StockItem model and reduce confusion around its purpose.
- [#11962](https://github.com/inventree/InvenTree/pull/11962) removes the "remote_image" field from the Part API endpoint, which (previously) allowed the user to specify a remote URL for an image to be downloaded and associated with the part. This field was removed due to security concerns around downloading images from arbitrary URLs. If you were using this field in an external client application, you will need to update your application to use the new "download_image_from_url" API endpoint instead. - [#11962](https://github.com/inventree/InvenTree/pull/11962) removes the "remote_image" field from the Part API endpoint, which (previously) allowed the user to specify a remote URL for an image to be downloaded and associated with the part. This field was removed due to security concerns around downloading images from arbitrary URLs. If you were using this field in an external client application, you will need to update your application to use the new "download_image_from_url" API endpoint instead.
## 1.3.0 - 2026-04-11 ## 1.3.0 - 2026-04-11
@@ -114,6 +114,9 @@ def reload_unit_registry():
reg.define('@alias degF = Fahrenheit') reg.define('@alias degF = Fahrenheit')
reg.define('@alias degK = Kelvin') reg.define('@alias degK = Kelvin')
# Override R as ohm (pint defines R as an SI prefix by default)
reg.define('R = ohm')
# Define some "standard" additional units # Define some "standard" additional units
reg.define('piece = 1') reg.define('piece = 1')
reg.define('each = 1 = ea') reg.define('each = 1 = ea')
+10
View File
@@ -293,6 +293,16 @@ class ConversionTest(TestCase):
) )
self.assertAlmostEqual(output, expected, 12) self.assertAlmostEqual(output, expected, 12)
# Test that 'R' is interpreted as ohms
# Ref: https://github.com/inventree/InvenTree/issues/12063
r_tests = [('8R6', 8.6), ('10R', 10), ('4R7', 4.7), ('100R', 100)]
for val, expected in r_tests:
output = InvenTree.conversion.convert_physical_value(
val, 'ohm', strip_units=True
)
self.assertAlmostEqual(output, expected, 6)
def test_scientific_notation(self): def test_scientific_notation(self):
"""Test that scientific notation is handled correctly.""" """Test that scientific notation is handled correctly."""
tests = [ tests = [
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
# Generated by Django 5.2.14 on 2026-06-02 06:22
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("stock", "0122_alter_stockitem_creation_date"),
]
operations = [
migrations.RemoveField(
model_name="stockitem",
name="review_needed",
),
]
-3
View File
@@ -448,7 +448,6 @@ class StockItem(
expiry_date: Expiry date of the StockItem (optional) expiry_date: Expiry date of the StockItem (optional)
stocktake_date: Date of last stocktake for this item stocktake_date: Date of last stocktake for this item
stocktake_user: User that performed the most recent stocktake stocktake_user: User that performed the most recent stocktake
review_needed: Flag if StockItem needs review
delete_on_deplete: If True, StockItem will be deleted when the stock level gets to zero delete_on_deplete: If True, StockItem will be deleted when the stock level gets to zero
status: Status of this StockItem (ref: stock.status_codes.StockStatus) status: Status of this StockItem (ref: stock.status_codes.StockStatus)
notes: Extra notes field notes: Extra notes field
@@ -1238,8 +1237,6 @@ class StockItem(
help_text=_('Date that this stock item was created'), help_text=_('Date that this stock item was created'),
) )
review_needed = models.BooleanField(default=False)
delete_on_deplete = models.BooleanField( delete_on_deplete = models.BooleanField(
default=default_delete_on_deplete, default=default_delete_on_deplete,
verbose_name=_('Delete on deplete'), verbose_name=_('Delete on deplete'),
@@ -4,7 +4,7 @@ import { apiUrl } from '@lib/functions/Api';
import { StylishText } from '@lib/index'; import { StylishText } from '@lib/index';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { BarChart } from '@mantine/charts'; import { BarChart } from '@mantine/charts';
import { Stack } from '@mantine/core'; import { Box, LoadingOverlay, Stack } from '@mantine/core';
import { useDocumentVisibility } from '@mantine/hooks'; import { useDocumentVisibility } from '@mantine/hooks';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@@ -84,13 +84,17 @@ function OrderHistoryComponent({
return ( return (
<Stack gap='xs'> <Stack gap='xs'>
<StylishText size='md'>{title}</StylishText> <StylishText size='md'>{title}</StylishText>
<Box>
<LoadingOverlay visible={query.isLoading || query.isFetching} />
<BarChart <BarChart
h={200} h={200}
data={chartData} data={chartData}
dataKey='month' dataKey='month'
series={[{ name: 'count', label: t`Completed`, color: 'blue.6' }]} series={[{ name: 'count', label: t`Completed`, color: 'blue.6' }]}
withYAxis={false} withYAxis={false}
yAxisProps={{ domain: [0, 'auto'] }}
/> />
</Box>
</Stack> </Stack>
); );
} }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+10 -4
View File
@@ -122,6 +122,13 @@ export default function StockDetail() {
} }
}); });
const { instance: part, instanceQuery: partQuery } = useInstance({
endpoint: ApiEndpoints.part_list,
pk: stockitem?.part,
hasPrimaryKey: true,
defaultValue: {}
});
const { instance: serialNumbers, instanceQuery: serialNumbersQuery } = const { instance: serialNumbers, instanceQuery: serialNumbersQuery } =
useInstance({ useInstance({
endpoint: ApiEndpoints.stock_serial_info, endpoint: ApiEndpoints.stock_serial_info,
@@ -884,9 +891,8 @@ export default function StockDetail() {
serial != '' && serial != '' &&
stockitem.quantity == 1; stockitem.quantity == 1;
const canConvert = // Allow variant conversion if the part is a variant, or if the part is a template
!!stockitem.part_detail?.variant_of || const canConvert = part?.variant_of || part?.is_template;
!!stockitem.part_detail?.is_template;
return [ return [
<AdminButton model={ModelType.stockitem} id={stockitem.pk} />, <AdminButton model={ModelType.stockitem} id={stockitem.pk} />,
@@ -967,7 +973,7 @@ export default function StockDetail() {
]} ]}
/> />
]; ];
}, [id, stockitem, user, stockAdjustActions.menuActions]); }, [id, stockitem, part, user, stockAdjustActions.menuActions]);
const stockBadges: ReactNode[] = useMemo(() => { const stockBadges: ReactNode[] = useMemo(() => {
let available = (stockitem?.quantity ?? 0) - (stockitem?.allocated ?? 0); let available = (stockitem?.quantity ?? 0) - (stockitem?.allocated ?? 0);