o2o-negosium-original/negodata/backend/common/anchoring/service.py
민헌 b362edf0d7 feat(negodata): 앵커링 v1.2 적용 — 칸 rate 조회·정수 박제·재생성 앵커 상속 폐지
- common/anchoring 이식 패키지 신설: 원본(schedules/anchoring)에서 읽기 경로 발췌
  (constants·base_table·service) + reader 이식판(Redis 미사용 — current_rates 뷰
  단일 쿼리, 실패·무이력 시 정적 테이블 폴백으로 견적 생성 무중단)
- _build_quotation: 목표가 산정과 앵커 산출 분리 — 칸(items.company_id ×
  quotations.supplier_type × 가격구간) rate 로 tp*(1000-rate)//1000 정수 박제,
  anchor_rate_permille 동시 기록. quotation_settings.anchoring_value 계산 사용 중단
- 재생성(regenerate_next_round): target_price 만 상속, 앵커는 생성 시점 rate 재계산
  (인수인계 규칙 1 — 상속 폐지)
- sessions 모델 anchor_rate_permille 매핑, crud get_item_companies 신설
- 테스트 6종 신설(스키마 부재 폴백·칸별 조정 반영·유형 미지정·재생성 재계산·
  bracket 경계 골든 벡터) — 전체 스위트 50 통과
- negodata 담당자 승인 하 직접 적용. 6개월 압축 시뮬레이션(격주 배치 13회,
  세션 522건)으로 박제→소비→재박제 루프·클램프·이월·이중소비 방지 검증 완료

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:37:27 +09:00

22 lines
1.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""순수 계산 함수 — DB 접근 없음. 원본: schedules/anchoring/src/anchoring/service.py 에서
읽기 경로(칸 해석·앵커가 산출) 두 함수만 발췌 이식. 표본 판정·평가 함수는 배치 전용이라 제외.
모든 산술은 정수(천분율 ‰). float 금지 — 1원 단위 내림의 정확성 보장.
"""
from bisect import bisect_right
from common.anchoring.constants import BRACKET_INDEX_MAX, UPPER_BOUNDS
def calc_bracket_index(target_price: int) -> int:
"""목표가 → 가격구간 인덱스(0-기반). 자릿수 계단식 사다리.
좌폐우개 [이전 ub, ub): 가격이 upper_bound 와 정확히 같으면 다음 칸.
1억 이상은 마지막 인덱스로 클램프. 정적 테이블 idx = 반환값 + 1"""
return min(bisect_right(UPPER_BOUNDS, target_price), BRACKET_INDEX_MAX)
def calc_anchor_price(target_price: int, rate_permille: int) -> int:
"""앵커링가 = 목표가 × (1 − A), 1원 단위 내림. (정수 연산만 — float 곱셈 재도입 금지)"""
return target_price * (1000 - rate_permille) // 1000