Compare commits

...

10 Commits

Author SHA1 Message Date
han0
c4c74cda65 fix: ci
Some checks failed
ci / build (push) Has been cancelled
2025-10-13 15:21:26 +08:00
han0
80272d2bf3 fix: 替换四六舍入为四五舍入 2025-06-05 18:57:35 +08:00
han0
1402b1a1e3 feat: 新增单独计算近半年均价的接口 2025-06-05 18:26:30 +08:00
han0
d752fe17c8 feat: 更新计算价格与位数同步 2025-05-26 17:44:09 +08:00
han0
463f9256fa fix: 修复材料半年均价显示位数异常的问题 2025-05-21 08:42:34 +08:00
han0
a10ab91a31 fix: 修复四舍五入计算问题 2025-05-19 18:12:03 +08:00
han0
7a9aa93a10 fix: 修复发布价材料重复的问题 2025-05-19 15:57:25 +08:00
han0
40c1593ff7 fix: 修复材料半年均价计算错误的问题 2025-05-07 12:48:55 +08:00
han0
6ada6371a3 fix: 修复计算机未按权重计算的问题 2025-05-07 08:35:52 +08:00
han0
bfb1315028 fix: 更新计算价的计算方式 2025-04-22 15:41:32 +08:00
8 changed files with 125 additions and 59 deletions

48
.gitea/workflows/ci.yaml Normal file
View File

@@ -0,0 +1,48 @@
name: ci
on:
push:
branches:
- test
env:
DEPLOY_PATH: /home/opt/app/material-api
DEPLOY_TEST_HOST_IP: 172.17.0.1
jobs:
build:
runs-on: ubuntu-latests
container:
image: python:3.7.16
steps:
- name: Checkout
run: |
git clone --depth 1 "http://test:89085111dd6939710a992d6404bd61a50e420685@8.138.239.222:20300/${GITHUB_REPOSITORY}.git" .
git checkout "${GITHUB_SHA}"
- name: Build
run: |
mkdir dist
PYTHONUSERBASE=$CI_PROJECT_DIR/home pip install --upgrade pip -i https://mirror.aliyun.com/pypi/simple --user
PYTHONUSERBASE=$CI_PROJECT_DIR/home pip install -r ./requirements.txt -i https://mirror.aliyun.com/pypi/simple --user
rsync -ha ./ ./dist --exclude=dist --exclude=.git --delete
- name: Deploy
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh -o StrictHostKeyChecking=no root@$DEPLOY_TEST_HOST_IP "mkdir -p $DEPLOY_PATH"
rsync -r ./dist/ ${DEPLOY_DEV_HOST_IP}:${DEPLOY_PATH} --delete
ssh ${SSH_OPTS} ${DEPLOY_DEV_HOST_IP} "cd ${DEPLOY_PATH} && source /etc/profile && docker-compose up -d --force-recreate"
ssh root@$DEPLOY_TEST_HOST_IP "rm -f $DEPLOY_PATH/*.jar"
scp ruoyi-admin/target/ruoyi-admin.jar root@$DEPLOY_TEST_HOST_IP:$DEPLOY_PATH/
ssh root@$DEPLOY_TEST_HOST_IP "mv $DEPLOY_PATH/ruoyi-admin.jar $DEPLOY_PATH/app.jar"
scp docker-compose.test.yml root@$DEPLOY_TEST_HOST_IP:$DEPLOY_PATH/
ssh root@$DEPLOY_TEST_HOST_IP "mv $DEPLOY_PATH/docker-compose.test.yml $DEPLOY_PATH/docker-compose.yml"
ssh root@$DEPLOY_TEST_HOST_IP "cd $DEPLOY_PATH && docker compose up -d --force-recreate"

View File

@@ -38,6 +38,7 @@ def refresh_task(task_id):
class CalculateQuery(BaseModel):
year: int = Field(title='年份')
month: int = Field(title='月份')
only_avg: int = Field(title='是否只计算均值', default=0)
@data.route('/calculate', methods=['GET'])
@@ -51,6 +52,6 @@ def start_calculate(query: CalculateQuery):
@data.route('/collect', methods=['GET'])
@siwa.doc(tags=[""], summary='触发计算任务', query=CalculateQuery)
def start_collect(query: CalculateQuery):
collect(year=query.year, month=query.month)
collect(year=query.year, month=query.month, only_avg=query.only_avg)
return Response()

View File

@@ -1,4 +1,4 @@
from decimal import Decimal
from decimal import Decimal, ROUND_HALF_UP
from commons.models.data_fujian import DataFujian
from commons.models.data_network import DataNetwork
@@ -37,7 +37,8 @@ class Helper:
class RoundMethod:
@staticmethod
def normal(n, round_bit):
result = round(n, round_bit)
q_ext = Decimal('0.' + '0' * round_bit)
result = Decimal(n).quantize(q_ext, rounding=ROUND_HALF_UP)
return result if round_bit != 0 else int(result)
@staticmethod
@@ -133,6 +134,7 @@ class Calculator:
}
def run(self):
self._get_weight()
self.price_ftb, self.fluctuating_ftb = self._get_ftb_price()
self.price_ss, self.fluctuating_ss = self._get_ss_price()
self.price_fhb, self.fluctuating_fhb = self._get_fhb_price()
@@ -190,17 +192,20 @@ class Calculator:
return getattr(self.previous_prices, 'price_recommend', 0)
def _get_calculate_price(self, round_dit=2):
prices = (self.price_ftb, self.price_ss, self.price_fhb, self.price_network, self.price_survey, self.price_last_month)
total = sum(float(i) for i in prices)
if total == 0:
prices = [
self.price_ftb * self.weight_ftb,
self.price_ss * self.weight_ss,
self.price_fhb * self.weight_fhb,
self.price_network * self.weight_network,
self.price_survey * self.weight_survey,
]
if sum(prices) == 0:
return 0
result = total / len([i for i in prices if i != 0])
result = round(result, round_dit)
result = sum(prices) / sum([self.weight_ftb, self.weight_ss, self.weight_fhb, self.weight_network, self.weight_survey])
result = self.round_method(result, self.round_bit)
return result
def _get_recommend_price(self, round_by=10):
self._get_weight()
if not self.previous_prices:
return 0, 0
@@ -226,7 +231,7 @@ class Calculator:
def _get_weight(self):
# 如果有上月数据按上月权重计算 无则平均数
if self._previous_prices:
if self.previous_prices:
self.weight_ftb = self._previous_prices.weight_ftb
self.weight_ss = self._previous_prices.weight_ss
self.weight_fhb = self._previous_prices.weight_fhb

View File

@@ -1,9 +1,10 @@
import datetime
import decimal
from decimal import Decimal
from sqlalchemy import func
from calculators import Helper
from commons.models.fujian_survey import FujianSurvey
from commons.models.price_publish import PricePublish
from commons.models.price_result import PriceResult
from commons.models.material import Material
@@ -11,7 +12,8 @@ from commons.models.material import Material
class Collector:
def __init__(self, year, month, force=True):
def __init__(self, year, month, force=True, only_avg=0):
self.only_avg = only_avg
self.year = year
self.month = month
self.force = True # todo-2 已发布的价格不在覆盖计算
@@ -21,14 +23,17 @@ class Collector:
self.material_codes = [m.code for m in self.materials if m.code]
# 缓存材料税率信息
self.tax_map = {m.code: m.tax for m in self.materials if m.code}
self.unit_map = {m.code: m.unit for m in self.materials if m.code}
self.name_map = {m.code: m.name for m in self.materials if m.code}
self.spec_map = {m.code: m.spec for m in self.materials if m.code}
self.round_bit_map = {m.code: m.round_bit for m in self.materials if m.code}
def get_avg(self):
query = PricePublish.get_query(material_id_in=self.material_codes)
query = PricePublish.query_previous_month(query, start_date=datetime.date(self.year, self.month, 1), count=6)
query = query.filter(PricePublish.type == '1')
query = query.with_entities(
PricePublish.material_id,
PricePublish.name,
PricePublish.spec,
func.avg(PricePublish.price),
func.avg(PricePublish.price_fuzhou),
func.avg(PricePublish.price_xiamen),
@@ -41,43 +46,39 @@ class Collector:
func.avg(PricePublish.price_ningde),
func.avg(PricePublish.price_pintan),
func.avg(PricePublish.price_zhangzhoukfq),
PricePublish.tax,
PricePublish.unit,
)
query = query.filter(PricePublish.price != 0)
query = query.group_by(
PricePublish.material_id,
PricePublish.name,
PricePublish.spec,
PricePublish.tax,
PricePublish.unit,
)
data = query.all()
for item in data:
material_id, name, spec, price, price_fuzhou, price_xiamen, price_putian, price_sanming, price_quanzhou, \
price_zhangzhou, price_nanpin, price_longyan, price_ningde, price_pintan, price_zhangzhoukfq, tax, unit, = item
material_id, price, price_fuzhou, price_xiamen, price_putian, price_sanming, price_quanzhou, \
price_zhangzhou, price_nanpin, price_longyan, price_ningde, price_pintan, price_zhangzhoukfq = item
display_digit = self.digit_map.get(material_id, 1)
round_bit = self.round_bit_map.get(material_id, 2)
q_ext = Decimal('0.' + '0' * round_bit)
PricePublish(
year=self.year,
month=self.month,
material_id=material_id,
name=name,
spec=spec,
price=round(price, 2),
price_fuzhou=round(price_fuzhou or 0, 2),
price_xiamen=round(price_xiamen or 0, 2),
price_putian=round(price_putian or 0, 2),
price_sanming=round(price_sanming or 0, 2),
price_quanzhou=round(price_quanzhou or 0, 2),
price_zhangzhou=round(price_zhangzhou or 0, 2),
price_nanpin=round(price_nanpin or 0, 2),
price_longyan=round(price_longyan or 0, 2),
price_ningde=round(price_ningde or 0, 2),
price_pintan=round(price_pintan or 0, 2),
price_zhangzhoukfq=round(price_zhangzhoukfq or 0, 2),
tax=self.tax_map.get(material_id, tax), # 从材料表获取税率
name=self.name_map.get(material_id, ''),
spec=self.spec_map.get(material_id, ''),
price=price.quantize(q_ext, decimal.ROUND_HALF_UP) if price else 0,
price_fuzhou=price_fuzhou.quantize(q_ext, decimal.ROUND_HALF_UP) if price_fuzhou else 0,
price_xiamen=price_xiamen.quantize(q_ext, decimal.ROUND_HALF_UP) if price_xiamen else 0,
price_putian=price_putian.quantize(q_ext, decimal.ROUND_HALF_UP) if price_putian else 0,
price_sanming=price_sanming.quantize(q_ext, decimal.ROUND_HALF_UP) if price_sanming else 0,
price_quanzhou=price_quanzhou.quantize(q_ext, decimal.ROUND_HALF_UP) if price_quanzhou else 0,
price_zhangzhou=price_zhangzhou.quantize(q_ext, decimal.ROUND_HALF_UP) if price_zhangzhou else 0,
price_nanpin=price_nanpin.quantize(q_ext, decimal.ROUND_HALF_UP) if price_nanpin else 0,
price_longyan=price_longyan.quantize(q_ext, decimal.ROUND_HALF_UP) if price_longyan else 0,
price_ningde=price_ningde.quantize(q_ext, decimal.ROUND_HALF_UP) if price_ningde else 0,
price_pintan=price_pintan.quantize(q_ext, decimal.ROUND_HALF_UP) if price_pintan else 0,
price_zhangzhoukfq=price_zhangzhoukfq.quantize(q_ext, decimal.ROUND_HALF_UP) if price_zhangzhoukfq else 0,
tax=self.tax_map.get(material_id, 0), # 从材料表获取税率
type=2,
unit=unit,
unit=self.unit_map.get(material_id, ''),
display_digit=display_digit,
).upsert()
@@ -120,9 +121,11 @@ class Collector:
def run(self):
# 当月价
# self.get_from_survey()
if not self.only_avg:
PricePublish.clean(self.year, self.month, type=1) # 清空当月价
self.get_from_result()
# 近半年平均价
PricePublish.clean(self.year, self.month, type=2) # 清空近半年平均价
self.get_avg()

View File

@@ -6,6 +6,12 @@ class BaseModelMixin:
def upsert(self):
result = self.find_by_key()
session = self._db.session
# # 住建厅数据初始化
# if result:
# result.price_fujian = self.price_fujian
# result.fluctuating_fujian = self.fluctuating_fujian
# session.add(result)
# session.commit()
if result:
session.delete(result)
session.flush()

View File

@@ -1,7 +1,8 @@
import datetime
from operator import and_
from dateutil.relativedelta import relativedelta
from sqlalchemy import Column, Integer, String, Numeric
from sqlalchemy import Column, Integer, String, Numeric, or_
from commons.models.mixin.base import BaseModelMixin
from commons.models.mixin.operation_track import OperationTrackMixin
@@ -40,8 +41,11 @@ class PricePublish(db.Model, Model, OperationTrackMixin, BaseModelMixin):
)
@classmethod
def clean(cls, year, month):
cls.query.filter(cls.year == year, cls.month == month).delete()
def clean(cls, year, month, type=None):
query = cls.query.filter(cls.year == year, cls.month == month)
if type:
query.filter(cls.type == type)
query.delete()
@classmethod
def get_by_key(cls, name, year, month, type):
@@ -71,10 +75,10 @@ class PricePublish(db.Model, Model, OperationTrackMixin, BaseModelMixin):
@classmethod
def query_previous_month(cls, query, start_date: datetime.date, count=6):
condition = False
for i in range(count):
for i in range(0, count):
date = start_date - relativedelta(months=i)
condition = condition or (cls.year == date.year and cls.month == date.month)
query.filter(condition)
condition = or_(condition, and_(cls.year == str(date.year), cls.month == str(date.month)))
query = query.filter(condition)
return query
@classmethod

View File

@@ -39,11 +39,11 @@ if __name__ == '__main__':
from core.factory import ClientApp
with ClientApp().app_context():
calculate(2024, 4)
calculate(2025, 5)
# for i in range(2, 12):
# calculate(2022, i+1)
# for i in range(0, 12):
# calculate(2023, i+1)
# for i in range(1, 5+1):
# calculate(2025, i)
# for i in range(6-1, 10):
# calculate(2024, i+1)

View File

@@ -2,12 +2,11 @@ from collectors import Collector
from commons.models.price_publish import PricePublish
def collect(year=2023, month=11):
def collect(year=2023, month=11, only_avg=0):
"""
整理发布价格
"""
PricePublish.clean(year, month) # 清空当月数据
collector = Collector(year, month)
collector = Collector(year, month, only_avg=only_avg)
collector.run()
@@ -15,11 +14,11 @@ if __name__ == '__main__':
from core.factory import ClientApp
with ClientApp().app_context():
collect(2023, 3)
collect(2025, 5)
# for i in range(2, 12):
# collect(2022, i + 1)
# for i in range(0, 12):
# for i in range(4):
# collect(2025, i + 1)
# for i in range(9,12):
# collect(2023, i + 1)
# for i in range(5, 10):
# for i in range(12):
# collect(2024, i + 1)