Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 1 | import frappe |
| 2 | from frappe.query_builder.functions import CombineDatetime, Sum |
| 3 | from frappe.utils import flt |
Rohit Waghchaure | c1132d1 | 2023-03-24 10:14:09 +0530 | [diff] [blame] | 4 | from frappe.utils.deprecations import deprecated |
Rohit Waghchaure | f4cfc58 | 2023-04-11 13:22:15 +0530 | [diff] [blame] | 5 | from pypika import Order |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 6 | |
| 7 | |
| 8 | class DeprecatedSerialNoValuation: |
Rohit Waghchaure | c1132d1 | 2023-03-24 10:14:09 +0530 | [diff] [blame] | 9 | @deprecated |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 10 | def calculate_stock_value_from_deprecarated_ledgers(self): |
| 11 | serial_nos = list( |
| 12 | filter(lambda x: x not in self.serial_no_incoming_rate and x, self.get_serial_nos()) |
| 13 | ) |
| 14 | |
| 15 | actual_qty = flt(self.sle.actual_qty) |
| 16 | |
| 17 | stock_value_change = 0 |
| 18 | if actual_qty < 0: |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 19 | if not self.sle.is_cancelled: |
| 20 | outgoing_value = self.get_incoming_value_for_serial_nos(serial_nos) |
| 21 | stock_value_change = -1 * outgoing_value |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 22 | |
| 23 | self.stock_value_change += stock_value_change |
| 24 | |
Rohit Waghchaure | c1132d1 | 2023-03-24 10:14:09 +0530 | [diff] [blame] | 25 | @deprecated |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 26 | def get_incoming_value_for_serial_nos(self, serial_nos): |
| 27 | # get rate from serial nos within same company |
| 28 | all_serial_nos = frappe.get_all( |
| 29 | "Serial No", fields=["purchase_rate", "name", "company"], filters={"name": ("in", serial_nos)} |
| 30 | ) |
| 31 | |
| 32 | incoming_values = 0.0 |
| 33 | for d in all_serial_nos: |
| 34 | if d.company == self.sle.company: |
Rohit Waghchaure | d3ceb07 | 2023-03-31 09:03:54 +0530 | [diff] [blame] | 35 | self.serial_no_incoming_rate[d.name] += flt(d.purchase_rate) |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 36 | incoming_values += flt(d.purchase_rate) |
| 37 | |
| 38 | # Get rate for serial nos which has been transferred to other company |
| 39 | invalid_serial_nos = [d.name for d in all_serial_nos if d.company != self.sle.company] |
| 40 | for serial_no in invalid_serial_nos: |
Rohit Waghchaure | f4cfc58 | 2023-04-11 13:22:15 +0530 | [diff] [blame] | 41 | table = frappe.qb.DocType("Stock Ledger Entry") |
| 42 | incoming_rate = ( |
| 43 | frappe.qb.from_(table) |
| 44 | .select(table.incoming_rate) |
| 45 | .where( |
| 46 | ( |
| 47 | (table.serial_no == serial_no) |
| 48 | | (table.serial_no.like(serial_no + "\n%")) |
| 49 | | (table.serial_no.like("%\n" + serial_no)) |
| 50 | | (table.serial_no.like("%\n" + serial_no + "\n%")) |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 51 | ) |
Rohit Waghchaure | f4cfc58 | 2023-04-11 13:22:15 +0530 | [diff] [blame] | 52 | & (table.company == self.sle.company) |
| 53 | & (table.serial_and_batch_bundle.isnull()) |
| 54 | & (table.actual_qty > 0) |
| 55 | & (table.is_cancelled == 0) |
| 56 | ) |
| 57 | .orderby(table.posting_date, order=Order.desc) |
| 58 | .limit(1) |
| 59 | ).run() |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 60 | |
Rohit Waghchaure | d3ceb07 | 2023-03-31 09:03:54 +0530 | [diff] [blame] | 61 | self.serial_no_incoming_rate[serial_no] += flt(incoming_rate[0][0]) if incoming_rate else 0 |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 62 | incoming_values += self.serial_no_incoming_rate[serial_no] |
| 63 | |
| 64 | return incoming_values |
| 65 | |
| 66 | |
| 67 | class DeprecatedBatchNoValuation: |
Rohit Waghchaure | c1132d1 | 2023-03-24 10:14:09 +0530 | [diff] [blame] | 68 | @deprecated |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 69 | def calculate_avg_rate_from_deprecarated_ledgers(self): |
Rohit Waghchaure | 5bb3173 | 2023-03-21 10:54:41 +0530 | [diff] [blame] | 70 | entries = self.get_sle_for_batches() |
| 71 | for ledger in entries: |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 72 | self.stock_value_differece[ledger.batch_no] += flt(ledger.batch_value) |
Rohit Waghchaure | 86da306 | 2023-03-20 14:15:34 +0530 | [diff] [blame] | 73 | self.available_qty[ledger.batch_no] += flt(ledger.batch_qty) |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 74 | |
Rohit Waghchaure | c1132d1 | 2023-03-24 10:14:09 +0530 | [diff] [blame] | 75 | @deprecated |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 76 | def get_sle_for_batches(self): |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 77 | if not self.batchwise_valuation_batches: |
| 78 | return [] |
| 79 | |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 80 | sle = frappe.qb.DocType("Stock Ledger Entry") |
| 81 | |
| 82 | timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime( |
| 83 | self.sle.posting_date, self.sle.posting_time |
| 84 | ) |
| 85 | if self.sle.creation: |
| 86 | timestamp_condition |= ( |
| 87 | CombineDatetime(sle.posting_date, sle.posting_time) |
| 88 | == CombineDatetime(self.sle.posting_date, self.sle.posting_time) |
| 89 | ) & (sle.creation < self.sle.creation) |
| 90 | |
Rohit Waghchaure | c2d7461 | 2023-03-29 11:40:36 +0530 | [diff] [blame] | 91 | query = ( |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 92 | frappe.qb.from_(sle) |
| 93 | .select( |
| 94 | sle.batch_no, |
| 95 | Sum(sle.stock_value_difference).as_("batch_value"), |
| 96 | Sum(sle.actual_qty).as_("batch_qty"), |
| 97 | ) |
| 98 | .where( |
| 99 | (sle.item_code == self.sle.item_code) |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 100 | & (sle.warehouse == self.sle.warehouse) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 101 | & (sle.batch_no.isin(self.batchwise_valuation_batches)) |
| 102 | & (sle.batch_no.isnotnull()) |
Rohit Waghchaure | e6143ab | 2023-03-13 14:51:43 +0530 | [diff] [blame] | 103 | & (sle.is_cancelled == 0) |
| 104 | ) |
| 105 | .where(timestamp_condition) |
| 106 | .groupby(sle.batch_no) |
Rohit Waghchaure | c2d7461 | 2023-03-29 11:40:36 +0530 | [diff] [blame] | 107 | ) |
| 108 | |
| 109 | if self.sle.name: |
| 110 | query = query.where(sle.name != self.sle.name) |
| 111 | |
| 112 | return query.run(as_dict=True) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 113 | |
| 114 | @deprecated |
| 115 | def calculate_avg_rate_for_non_batchwise_valuation(self): |
| 116 | if not self.non_batchwise_valuation_batches: |
| 117 | return |
| 118 | |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 119 | self.non_batchwise_balance_value = 0.0 |
| 120 | self.non_batchwise_balance_qty = 0.0 |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 121 | |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 122 | self.set_balance_value_for_non_batchwise_valuation_batches() |
| 123 | |
| 124 | for batch_no, ledger in self.batch_nos.items(): |
| 125 | if batch_no not in self.non_batchwise_valuation_batches: |
| 126 | continue |
| 127 | |
| 128 | self.batch_avg_rate[batch_no] = ( |
| 129 | self.non_batchwise_balance_value / self.non_batchwise_balance_qty |
| 130 | ) |
| 131 | |
| 132 | stock_value_change = self.batch_avg_rate[batch_no] * ledger.qty |
| 133 | self.stock_value_change += stock_value_change |
| 134 | |
| 135 | frappe.db.set_value( |
| 136 | "Serial and Batch Entry", |
| 137 | ledger.name, |
| 138 | { |
| 139 | "stock_value_difference": stock_value_change, |
| 140 | "incoming_rate": self.batch_avg_rate[batch_no], |
| 141 | }, |
| 142 | ) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 143 | |
| 144 | @deprecated |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 145 | def set_balance_value_for_non_batchwise_valuation_batches(self): |
| 146 | self.set_balance_value_from_sl_entries() |
| 147 | self.set_balance_value_from_bundle() |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 148 | |
| 149 | @deprecated |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 150 | def set_balance_value_from_sl_entries(self) -> None: |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 151 | sle = frappe.qb.DocType("Stock Ledger Entry") |
| 152 | batch = frappe.qb.DocType("Batch") |
| 153 | |
| 154 | timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime( |
| 155 | self.sle.posting_date, self.sle.posting_time |
| 156 | ) |
| 157 | if self.sle.creation: |
| 158 | timestamp_condition |= ( |
| 159 | CombineDatetime(sle.posting_date, sle.posting_time) |
| 160 | == CombineDatetime(self.sle.posting_date, self.sle.posting_time) |
| 161 | ) & (sle.creation < self.sle.creation) |
| 162 | |
| 163 | query = ( |
| 164 | frappe.qb.from_(sle) |
| 165 | .inner_join(batch) |
| 166 | .on(sle.batch_no == batch.name) |
| 167 | .select( |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 168 | sle.batch_no, |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 169 | Sum(sle.actual_qty).as_("batch_qty"), |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 170 | Sum(sle.stock_value_difference).as_("batch_value"), |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 171 | ) |
| 172 | .where( |
| 173 | (sle.item_code == self.sle.item_code) |
| 174 | & (sle.warehouse == self.sle.warehouse) |
| 175 | & (sle.batch_no.isnotnull()) |
| 176 | & (batch.use_batchwise_valuation == 0) |
| 177 | & (sle.is_cancelled == 0) |
| 178 | ) |
| 179 | .where(timestamp_condition) |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 180 | .groupby(sle.batch_no) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 181 | ) |
| 182 | |
| 183 | if self.sle.name: |
| 184 | query = query.where(sle.name != self.sle.name) |
| 185 | |
| 186 | for d in query.run(as_dict=True): |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 187 | self.non_batchwise_balance_value += flt(d.batch_value) |
| 188 | self.non_batchwise_balance_qty += flt(d.batch_qty) |
| 189 | self.available_qty[d.batch_no] += flt(d.batch_qty) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 190 | |
| 191 | @deprecated |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 192 | def set_balance_value_from_bundle(self) -> None: |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 193 | bundle = frappe.qb.DocType("Serial and Batch Bundle") |
| 194 | bundle_child = frappe.qb.DocType("Serial and Batch Entry") |
| 195 | batch = frappe.qb.DocType("Batch") |
| 196 | |
| 197 | timestamp_condition = CombineDatetime( |
| 198 | bundle.posting_date, bundle.posting_time |
| 199 | ) < CombineDatetime(self.sle.posting_date, self.sle.posting_time) |
| 200 | |
| 201 | if self.sle.creation: |
| 202 | timestamp_condition |= ( |
| 203 | CombineDatetime(bundle.posting_date, bundle.posting_time) |
| 204 | == CombineDatetime(self.sle.posting_date, self.sle.posting_time) |
| 205 | ) & (bundle.creation < self.sle.creation) |
| 206 | |
| 207 | query = ( |
| 208 | frappe.qb.from_(bundle) |
| 209 | .inner_join(bundle_child) |
| 210 | .on(bundle.name == bundle_child.parent) |
| 211 | .inner_join(batch) |
| 212 | .on(bundle_child.batch_no == batch.name) |
| 213 | .select( |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 214 | bundle_child.batch_no, |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 215 | Sum(bundle_child.qty).as_("batch_qty"), |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 216 | Sum(bundle_child.stock_value_difference).as_("batch_value"), |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 217 | ) |
| 218 | .where( |
| 219 | (bundle.item_code == self.sle.item_code) |
| 220 | & (bundle.warehouse == self.sle.warehouse) |
| 221 | & (bundle_child.batch_no.isnotnull()) |
| 222 | & (batch.use_batchwise_valuation == 0) |
| 223 | & (bundle.is_cancelled == 0) |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 224 | & (bundle.docstatus == 1) |
Rohit Waghchaure | f8bf4aa | 2023-04-02 13:13:42 +0530 | [diff] [blame] | 225 | & (bundle.type_of_transaction.isin(["Inward", "Outward"])) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 226 | ) |
| 227 | .where(timestamp_condition) |
Rohit Waghchaure | f704eb7 | 2023-03-30 11:32:39 +0530 | [diff] [blame] | 228 | .groupby(bundle_child.batch_no) |
| 229 | ) |
| 230 | |
| 231 | if self.sle.serial_and_batch_bundle: |
| 232 | query = query.where(bundle.name != self.sle.serial_and_batch_bundle) |
| 233 | |
| 234 | for d in query.run(as_dict=True): |
Rohit Waghchaure | 40ab3bd | 2023-06-01 16:08:49 +0530 | [diff] [blame] | 235 | self.non_batchwise_balance_value += flt(d.batch_value) |
| 236 | self.non_batchwise_balance_qty += flt(d.batch_qty) |
| 237 | self.available_qty[d.batch_no] += flt(d.batch_qty) |