mcpField
C
contract-management

contract-management

github.com/kishorkukrejaその他8470 回インストール3 週間前に更新
リポジトリ

contract-management について

調達、法務、契約管理チーム向けの契約管理スキルです。契約の開始から交渉、更新または終了までを扱い、義務や支出のコンプライアンス管理、更新分析、ポートフォリオ分析の枠組みを示します。

主な機能

  1. 01契約ライフサイクルの枠組み
  2. 02交渉条件と戦略の整理
  3. 03契約義務の追跡
  4. 04支出コンプライアンス分析
  5. 05更新・ポートフォリオ分析

活用シーン

  1. 01契約更新と再交渉の計画
  2. 02義務と期限の追跡
  3. 03契約に対する購買支出の確認
  4. 04契約ポートフォリオのリスクと機会の特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill contract-management

インストール後、Claude Code で/contract-managementを入力して読み込まれたか確認します。

詳細

契約管理

調達契約の管理と交渉に関する専門家です。組織が契約のライフサイクル全体を通じてサプライヤー契約を管理し、有利な条件を交渉し、コンプライアンスを確保するとともに、契約価値とパフォーマンスを最適化できるよう支援します。

初期評価

契約を管理する前に、以下を把握します。

  1. 契約ポートフォリオの状況

    • 有効な契約はいくつありますか?
    • 契約総額(TCV)はいくらですか?
    • 契約の種類は何ですか?(MSA、SOW、購買契約)
    • 現在の課題や問題点は何ですか?
  2. 管理の成熟度

    • 既存の契約管理プロセスはありますか?
    • CLM(契約ライフサイクル管理)システムを導入していますか?
    • 契約コンプライアンスを監視していますか?
    • 更新を追跡するプロセスはありますか?
  3. ビジネス目標

    • 主な目標は何ですか?(コスト削減、リスク軽減、コンプライアンス)
    • 主要業績評価指標は何ですか?
    • 契約の標準化レベルはどの程度ですか?
    • 承認ワークフローはどのようになっていますか?
  4. リソースとシステム

    • 法務チームはどの程度関与していますか?
    • 調達チームの組織体制はどのようになっていますか?
    • 文書管理システムはありますか?
    • ERP/P2P と連携していますか?

契約ライフサイクル管理フレームワーク

契約ライフサイクルの各段階

1. 契約前(開始)

  • ニーズの特定
  • ビジネスケースの承認
  • サプライヤーの選定
  • RFP/交渉の準備

2. 交渉

  • 条件条項
  • 価格と支払条件
  • SLA と KPI
  • リスク分担
  • 法務レビュー

3. 締結

  • 契約への署名
  • 承認と回付
  • 契約リポジトリへの保存
  • 関係者への通知

4. 管理

  • 義務の追跡
  • パフォーマンスの監視
  • 請求書と支払いの管理
  • 変更依頼
  • 関係管理

5. 更新/終了

  • パフォーマンスレビュー
  • 更新の判断
  • 再交渉
  • 移行計画
  • 契約の終了処理

契約交渉戦略

交渉の準備

調査と分析:

  • 市場ベンチマークと価格
  • サプライヤーの財務健全性
  • BATNA(交渉による合意が成立しない場合の最善の代替案)
  • 交渉を打ち切る基準
  • 関係者の要件

交渉上の優位性:

  • 取引量/支出規模
  • 複数年契約のコミットメント
  • 優先サプライヤーの地位
  • 支払条件(早期支払い)
  • 事業成長の可能性
  • リファレンス/推薦文
交渉する主な条件

1. 価格条件

class PricingStructure:
    """Model different pricing structures for negotiation"""

    @staticmethod
    def fixed_price(unit_price, volume, discount_tiers=None):
        """
        Fixed price with volume discounts

        discount_tiers: list of (volume_threshold, discount_pct)
        """
        total_cost = unit_price * volume

        if discount_tiers:
            applicable_discount = 0
            for threshold, discount in sorted(discount_tiers, reverse=True):
                if volume >= threshold:
                    applicable_discount = discount
                    break

            total_cost = total_cost * (1 - applicable_discount)

        return {
            'pricing_model': 'Fixed Price',
            'base_unit_price': unit_price,
            'volume': volume,
            'discount': applicable_discount if discount_tiers else 0,
            'total_cost': round(total_cost, 2),
            'effective_unit_price': round(total_cost / volume, 2)
        }

    @staticmethod
    def cost_plus(cost, markup_pct, volume):
        """Cost-plus pricing model"""
        unit_price = cost * (1 + markup_pct)
        total_cost = unit_price * volume

        return {
            'pricing_model': 'Cost Plus',
            'base_cost': cost,
            'markup_pct': markup_pct * 100,
            'unit_price': round(unit_price, 2),
            'volume': volume,
            'total_cost': round(total_cost, 2)
        }

    @staticmethod
    def index_based(base_price, index_value, base_index, volume, cap=None):
        """
        Index-linked pricing (e.g., commodity, inflation)

        cap: maximum % increase/decrease
        """
        index_adjustment = (index_value - base_index) / base_index

        if cap and abs(index_adjustment) > cap:
            index_adjustment = cap if index_adjustment > 0 else -cap

        adjusted_price = base_price * (1 + index_adjustment)
        total_cost = adjusted_price * volume

        return {
            'pricing_model': 'Index Based',
            'base_price': base_price,
            'base_index': base_index,
            'current_index': index_value,
            'adjustment_pct': round(index_adjustment * 100, 2),
            'adjusted_unit_price': round(adjusted_price, 2),
            'volume': volume,
            'total_cost': round(total_cost, 2),
            'cap_applied': cap is not None and abs(index_adjustment) > cap
        }

    @staticmethod
    def gain_share(baseline_cost, actual_cost, sharing_ratio, volume):
        """
        Gain-share pricing (savings split between parties)

        sharing_ratio: % of savings to buyer (e.g., 0.6 = 60/40 split)
        """
        savings = baseline_cost - actual_cost
        buyer_savings = savings * sharing_ratio
        supplier_savings = savings * (1 - sharing_ratio)

        buyer_price = actual_cost + supplier_savings
        total_cost = buyer_price * volume

        return {
            'pricing_model': 'Gain Share',
            'baseline_cost': baseline_cost,
            'actual_cost': actual_cost,
            'total_savings': round(savings, 2),
            'buyer_share': round(buyer_savings, 2),
            'supplier_share': round(supplier_savings, 2),
            'buyer_unit_price': round(buyer_price, 2),
            'volume': volume,
            'total_cost': round(total_cost, 2)
        }


# Example: Compare pricing models
volume = 100000

fixed = PricingStructure.fixed_price(
    unit_price=10.00,
    volume=volume,
    discount_tiers=[(50000, 0.05), (100000, 0.08)]
)

cost_plus = PricingStructure.cost_plus(
    cost=8.50,
    markup_pct=0.15,
    volume=volume
)

index = PricingStructure.index_based(
    base_price=10.00,
    index_value=105,
    base_index=100,
    volume=volume,
    cap=0.10  # 10% cap
)

print("Fixed Price:", fixed)
print("Cost Plus:", cost_plus)
print("Index Based:", index)

2. 支払条件

  • 標準:Net 30、Net 60、Net 90
  • 早期支払い割引:2/10 Net 30
  • 支払いマイルストーン(サービスの場合)
  • 前払いと後払い
  • 電子請求書と自動支払い
def evaluate_payment_terms(invoice_amount, terms_options):
    """
    Evaluate different payment terms

    terms_options: list of dicts with payment terms
    """

    results = []

    for option in terms_options:
        term_type = option['type']
        days = option.get('days', 30)
        discount = option.get('discount_pct', 0)

        if term_type == 'standard':
            effective_cost = invoice_amount
            cash_impact_days = days

        elif term_type == 'early_discount':
            discount_days = option.get('discount_days', 10)
            if option.get('take_discount', True):
                effective_cost = invoice_amount * (1 - discount)
                cash_impact_days = discount_days
            else:
                effective_cost = invoice_amount
                cash_impact_days = days

        # Annualized cost of capital
        cost_of_capital_annual = 0.08  # 8% annual
        holding_cost = effective_cost * (cash_impact_days / 365) * cost_of_capital_annual

        total_cost = effective_cost + holding_cost

        results.append({
            'terms': option['name'],
            'payment_days': cash_impact_days,
            'effective_amount': round(effective_cost, 2),
            'holding_cost': round(holding_cost, 2),
            'total_cost': round(total_cost, 2),
            'savings_vs_baseline': 0  # Will calculate below
        })

    # Calculate savings vs. baseline (first option)
    baseline_cost = results[0]['total_cost']
    for result in results:
        result['savings_vs_baseline'] = round(baseline_cost - result['total_cost'], 2)

    return results


# Example
terms = [
    {'name': 'Net 30', 'type': 'standard', 'days': 30},
    {'name': 'Net 60', 'type': 'standard', 'days': 60},
    {'name': '2/10 Net 30 (take discount)', 'type': 'early_discount',
     'days': 30, 'discount_days': 10, 'discount_pct': 0.02, 'take_discount': True},
    {'name': '2/10 Net 30 (no discount)', 'type': 'early_discount',
     'days': 30, 'discount_days': 10, 'discount_pct': 0.02, 'take_discount': False},
]

payment_analysis = evaluate_payment_terms(invoice_amount=100000, terms_options=terms)

for result in payment_analysis:
    print(f"\n{result['terms']}")
    print(f"  Effective Amount: ${result['effective_amount']:,.2f}")
    print(f"  Total Cost: ${result['total_cost']:,.2f}")
    print(f"  Savings: ${result['savings_vs_baseline']:,.2f}")

3. サービスレベル契約(SLA)

class SLAManager:
    """Manage and track Service Level Agreements"""

    def __init__(self, contract_id):
        self.contract_id = contract_id
        self.slas = []

    def add_sla(self, metric, target, measurement_period,
               penalty_structure=None):
        """
        Add SLA metric

        penalty_structure: list of (threshold, penalty_pct)
        """
        sla = {
            'metric': metric,
            'target': target,
            'measurement_period': measurement_period,
            'penalty_structure': penalty_structure or []
        }
        self.slas.append(sla)

    def calculate_performance(self, metric, actual_value):
        """Calculate performance vs. SLA target"""

        sla = next((s for s in self.slas if s['metric'] == metric), None)
        if not sla:
            return None

        target = sla['target']

        # Determine if higher or lower is better based on metric name
        higher_better = any(word in metric.lower()
                          for word in ['uptime', 'delivery', 'fill', 'accuracy'])

        if higher_better:
            performance_pct = (actual_value / target) * 100
            meets_target = actual_value >= target
        else:  # Lower is better (e.g., defect rate, lead time)
            performance_pct = (target / actual_value) * 100
            meets_target = actual_value <= target

        # Calculate penalty if applicable
        penalty_pct = 0
        if not meets_target and sla['penalty_structure']:
            variance = abs(actual_value - target) / target

            for threshold, penalty in sorted(sla['penalty_structure'], reverse=True):
                if variance >= threshold:
                    penalty_pct = penalty
                    break

        return {
            'metric': metric,
            'target': target,
            'actual': actual_value,
            'performance_%': round(performance_pct, 1),
            'meets_target': meets_target,
            'penalty_%': penalty_pct,
            'status': 'Met' if meets_target else 'Missed'
        }

    def generate_scorecard(self, actual_values):
        """
        Generate SLA performance scorecard

        actual_values: dict {metric: actual_value}
        """
        scorecard = []

        for metric, actual in actual_values.items():
            result = self.calculate_performance(metric, actual)
            if result:
                scorecard.append(result)

        # Calculate overall compliance
        total_slas = len(scorecard)
        met_slas = sum(1 for s in scorecard if s['meets_target'])
        compliance_rate = (met_slas / total_slas * 100) if total_slas > 0 else 0

        return {
            'contract_id': self.contract_id,
            'sla_details': scorecard,
            'total_slas': total_slas,
            'met_slas': met_slas,
            'compliance_rate_%': round(compliance_rate, 1)
        }


# Example usage
sla_manager = SLAManager(contract_id='CNT-12345')

# Add SLAs with penalty structures
sla_manager.add_sla(
    metric='On-Time Delivery %',
    target=95.0,
    measurement_period='monthly',
    penalty_structure=[
        (0.05, 0.02),  # 5% miss = 2% penalty
        (0.10, 0.05),  # 10% miss = 5% penalty
        (0.15, 0.10),  # 15% miss = 10% penalty
    ]
)

sla_manager.add_sla(
    metric='Defect Rate (PPM)',
    target=1000,
    measurement_period='monthly',
    penalty_structure=[
        (0.20, 0.03),  # 20% over = 3% penalty
        (0.50, 0.05),  # 50% over = 5% penalty
    ]
)

sla_manager.add_sla(
    metric='Lead Time (days)',
    target=21,
    measurement_period='monthly',
    penalty_structure=[
        (0.10, 0.01),  # 10% over = 1% penalty
        (0.25, 0.03),  # 25% over = 3% penalty
    ]
)

# Evaluate actual performance
actual_performance = {
    'On-Time Delivery %': 92.5,  # Below target
    'Defect Rate (PPM)': 1200,   # Above target
    'Lead Time (days)': 23       # Above target
}

scorecard = sla_manager.generate_scorecard(actual_performance)

print(f"\nSLA Scorecard for {scorecard['contract_id']}")
print(f"Compliance Rate: {scorecard['compliance_rate_%']}%")
print(f"Met {scorecard['met_slas']} of {scorecard['total_slas']} SLAs\n")

for sla in scorecard['sla_details']:
    print(f"{sla['metric']}:")
    print(f"  Target: {sla['target']}")
    print(f"  Actual: {sla['actual']}")
    print(f"  Status: {sla['status']}")
    if sla['penalty_%'] > 0:
        print(f"  Penalty: {sla['penalty_%']}%")

4. リスク分担と補償

  • 責任上限
  • 保険要件
  • 保証条件
  • 不可抗力
  • 知的財産権に関する補償
  • データセキュリティとプライバシー

5. 変更管理

  • 変更依頼プロセス
  • スコープ変更時の価格設定
  • スケジュールの調整
  • 承認要件

6. 契約解除条項

  • 任意解除
  • 正当事由による解除
  • 通知期間
  • 終了時の義務
  • 移行支援

契約コンプライアンスの監視

義務の追跡
import pandas as pd
from datetime import datetime, timedelta

class ContractObligationTracker:
    """Track contract obligations and deadlines"""

    def __init__(self):
        self.obligations = []

    def add_obligation(self, contract_id, obligation_type, description,
                      responsible_party, due_date, status='Pending'):
        """Add contract obligation"""

        self.obligations.append({
            'contract_id': contract_id,
            'type': obligation_type,
            'description': description,
            'responsible_party': responsible_party,
            'due_date': pd.to_datetime(due_date),
            'status': status,
            'added_date': datetime.now()
        })

    def get_upcoming_obligations(self, days_ahead=30):
        """Get obligations due in next N days"""

        df = pd.DataFrame(self.obligations)

        if df.empty:
            return df

        # Filter pending obligations
        df = df[df['status'] == 'Pending']

        # Filter by date range
        today = pd.Timestamp.now()
        future_date = today + timedelta(days=days_ahead)

        df = df[(df['due_date'] >= today) & (df['due_date'] <= future_date)]

        # Sort by due date
        df = df.sort_values('due_date')

        # Add days until due
        df['days_until_due'] = (df['due_date'] - today).dt.days

        return df

    def get_overdue_obligations(self):
        """Get overdue obligations"""

        df = pd.DataFrame(self.obligations)

        if df.empty:
            return df

        # Filter pending and overdue
        df = df[df['status'] == 'Pending']
        today = pd.Timestamp.now()
        df = df[df['due_date'] < today]

        # Sort by due date (oldest first)
        df = df.sort_values('due_date')

        # Add days overdue
        df['days_overdue'] = (today - df['due_date']).dt.days

        return df

    def update_status(self, contract_id, description, new_status):
        """Update obligation status"""

        for obligation in self.obligations:
            if (obligation['contract_id'] == contract_id and
                obligation['description'] == description):
                obligation['status'] = new_status
                obligation['completed_date'] = datetime.now()
                break


# Example usage
tracker = ContractObligationTracker()

# Add various obligations
tracker.add_obligation(
    contract_id='CNT-001',
    obligation_type='Deliverable',
    description='Submit quarterly business review',
    responsible_party='Supplier',
    due_date='2026-04-01'
)

tracker.add_obligation(
    contract_id='CNT-001',
    obligation_type='Payment',
    description='Monthly payment due',
    responsible_party='Buyer',
    due_date='2026-02-15'
)

tracker.add_obligation(
    contract_id='CNT-002',
    obligation_type='Audit',
    description='Annual security audit',
    responsible_party='Supplier',
    due_date='2026-03-15'
)

tracker.add_obligation(
    contract_id='CNT-003',
    obligation_type='Renewal Decision',
    description='Notify renewal or termination',
    responsible_party='Buyer',
    due_date='2026-01-30'  # Overdue
)

# Check upcoming obligations
upcoming = tracker.get_upcoming_obligations(days_ahead=60)
print("Upcoming Obligations:")
print(upcoming[['contract_id', 'description', 'due_date', 'days_until_due']])

# Check overdue
overdue = tracker.get_overdue_obligations()
print("\nOverdue Obligations:")
print(overdue[['contract_id', 'description', 'days_overdue']])
支出コンプライアンスの監視
def analyze_contract_compliance(actual_spend_df, contracts_df):
    """
    Analyze spend compliance with contracts

    actual_spend_df: DataFrame with actual purchases
    contracts_df: DataFrame with contract details
    """

    # Merge actual spend with contracts
    spend_with_contract = actual_spend_df.merge(
        contracts_df[['supplier_name', 'category', 'contract_id',
                     'contracted_price', 'volume_commitment']],
        on=['supplier_name', 'category'],
        how='left'
    )

    # Calculate compliance metrics
    compliance_summary = []

    for contract_id in contracts_df['contract_id'].unique():
        contract_data = spend_with_contract[
            spend_with_contract['contract_id'] == contract_id
        ]

        if len(contract_data) == 0:
            continue

        contract = contracts_df[contracts_df['contract_id'] == contract_id].iloc[0]

        total_spend = contract_data['spend_amount'].sum()
        total_volume = contract_data['volume'].sum()
        volume_commitment = contract['volume_commitment']

        # Volume compliance
        volume_achievement = total_volume / volume_commitment * 100

        # Price compliance
        contract_data['price_variance'] = (
            contract_data['unit_price'] - contract_data['contracted_price']
        ) / contract_data['contracted_price']

        avg_price_variance = contract_data['price_variance'].mean() * 100
        price_compliant = (contract_data['price_variance'].abs() < 0.02).mean() * 100

        compliance_summary.append({
            'contract_id': contract_id,
            'supplier': contract['supplier_name'],
            'category': contract['category'],
            'total_spend': total_spend,
            'volume_commitment': volume_commitment,
            'actual_volume': total_volume,
            'volume_achievement_%': round(volume_achievement, 1),
            'avg_price_variance_%': round(avg_price_variance, 1),
            'price_compliance_%': round(price_compliant, 1),
            'status': 'Compliant' if (volume_achievement >= 80 and
                                     abs(avg_price_variance) < 5) else 'Non-Compliant'
        })

    return pd.DataFrame(compliance_summary)

契約更新管理

更新判断のフレームワーク
class ContractRenewalAnalysis:
    """Analyze contract for renewal decision"""

    def __init__(self, contract_id, current_terms):
        self.contract_id = contract_id
        self.current_terms = current_terms
        self.performance_data = {}
        self.market_data = {}

    def add_performance_data(self, sla_compliance, quality_score,
                            delivery_score, relationship_score):
        """Add supplier performance data"""
        self.performance_data = {
            'sla_compliance_%': sla_compliance,
            'quality_score': quality_score,  # 0-10
            'delivery_score': delivery_score,  # 0-10
            'relationship_score': relationship_score  # 0-10
        }

    def add_market_data(self, market_price, inflation_rate,
                       competitive_alternatives):
        """Add market intelligence"""
        self.market_data = {
            'market_price': market_price,
            'current_price': self.current_terms['price'],
            'inflation_rate': inflation_rate,
            'competitive_alternatives': competitive_alternatives
        }

    def calculate_renewal_score(self):
        """Calculate overall renewal recommendation score"""

        score = 0
        max_score = 100
        factors = []

        # Performance scoring (40 points)
        if self.performance_data:
            perf = self.performance_data

            # SLA compliance (15 points)
            sla_points = (perf['sla_compliance_%'] / 100) * 15
            score += sla_points

            if perf['sla_compliance_%'] >= 95:
                factors.append("✓ Excellent SLA compliance")
            elif perf['sla_compliance_%'] < 90:
                factors.append("✗ Poor SLA compliance")

            # Quality (10 points)
            quality_points = (perf['quality_score'] / 10) * 10
            score += quality_points

            # Delivery (10 points)
            delivery_points = (perf['delivery_score'] / 10) * 10
            score += delivery_points

            # Relationship (5 points)
            relationship_points = (perf['relationship_score'] / 10) * 5
            score += relationship_points

        # Price competitiveness (30 points)
        if self.market_data:
            market = self.market_data

            price_variance = (market['current_price'] - market['market_price']) / market['market_price']

            if price_variance <= -0.05:  # 5% below market
                price_points = 30
                factors.append("✓ Very competitive pricing")
            elif price_variance <= 0:
                price_points = 25
                factors.append("✓ Competitive pricing")
            elif price_variance <= 0.05:
                price_points = 20
                factors.append("~ At market price")
            elif price_variance <= 0.10:
                price_points = 10
                factors.append("✗ Above market price")
            else:
                price_points = 0
                factors.append("✗✗ Significantly above market")

            score += price_points

            # Competitive alternatives (10 points)
            if market['competitive_alternatives'] == 0:
                score += 0
                factors.append("✗ No alternatives (locked in)")
            elif market['competitive_alternatives'] <= 2:
                score += 5
                factors.append("~ Limited alternatives")
            else:
                score += 10
                factors.append("✓ Multiple alternatives available")

        # Switching cost consideration (20 points)
        switching_cost = self.current_terms.get('switching_cost', 'medium')
        if switching_cost == 'low':
            score += 20
        elif switching_cost == 'medium':
            score += 12
        else:  # high
            score += 5
            factors.append("⚠ High switching cost")

        # Normalize to 100
        score = min(score, max_score)

        # Recommendation
        if score >= 80:
            recommendation = "Renew - Strong Performance"
        elif score >= 60:
            recommendation = "Renew with Renegotiation"
        elif score >= 40:
            recommendation = "Competitive Bid"
        else:
            recommendation = "Replace - Poor Value"

        return {
            'contract_id': self.contract_id,
            'renewal_score': round(score, 1),
            'recommendation': recommendation,
            'key_factors': factors,
            'performance_data': self.performance_data,
            'market_data': self.market_data
        }


# Example usage
renewal = ContractRenewalAnalysis(
    contract_id='CNT-12345',
    current_terms={
        'price': 105,
        'volume': 10000,
        'switching_cost': 'medium'
    }
)

renewal.add_performance_data(
    sla_compliance=94.5,
    quality_score=8.5,
    delivery_score=9.0,
    relationship_score=8.0
)

renewal.add_market_data(
    market_price=100,
    inflation_rate=0.03,
    competitive_alternatives=3
)

result = renewal.calculate_renewal_score()

print(f"\nRenewal Analysis: {result['contract_id']}")
print(f"Renewal Score: {result['renewal_score']}/100")
print(f"Recommendation: {result['recommendation']}")
print("\nKey Factors:")
for factor in result['key_factors']:
    print(f"  {factor}")

契約分析

ポートフォリオ分析
def contract_portfolio_analytics(contracts_df):
    """
    Analyze contract portfolio

    contracts_df: DataFrame with contract details
    """

    analytics = {}

    # Total contract value
    analytics['total_contract_value'] = contracts_df['annual_value'].sum()

    # Number of contracts
    analytics['total_contracts'] = len(contracts_df)

    # Contracts by status
    analytics['by_status'] = contracts_df.groupby('status')['annual_value'].agg([
        ('count', 'count'),
        ('value', 'sum')
    ]).to_dict('index')

    # Contracts expiring in next 90 days
    today = pd.Timestamp.now()
    expiry_threshold = today + timedelta(days=90)

    expiring_soon = contracts_df[
        (contracts_df['end_date'] >= today) &
        (contracts_df['end_date'] <= expiry_threshold)
    ]

    analytics['expiring_90_days'] = {
        'count': len(expiring_soon),
        'value': expiring_soon['annual_value'].sum(),
        'contracts': expiring_soon['contract_id'].tolist()
    }

    # Average contract value
    analytics['avg_contract_value'] = contracts_df['annual_value'].mean()

    # Contract concentration (top 10 by value)
    top_10_value = contracts_df.nlargest(10, 'annual_value')['annual_value'].sum()
    analytics['top_10_concentration_%'] = (
        top_10_value / analytics['total_contract_value'] * 100
    )

    # By category
    analytics['by_category'] = contracts_df.groupby('category')['annual_value'].agg([
        ('count', 'count'),
        ('value', 'sum')
    ]).to_dict('index')

    return analytics

ツールとライブラリ

Python ライブラリ

文書管理:

  • python-docx:Microsoft Word 文書
  • PyPDF2、pdfplumber:PDF の解析
  • spacy、nltk:自然言語処理
  • pandas:データ分析

契約分析:

  • numpy:数値分析
  • matplotlib、seaborn:可視化
  • sklearn:契約分析のための機械学習
商用ソフトウェア

契約ライフサイクル管理(CLM):

  • Coupa CLM:契約管理プラットフォーム
  • SAP Ariba Contracts:契約ライフサイクル
  • Icertis:エンタープライズ向け契約管理
  • Agiloft:AI を活用した CLM
  • DocuSign CLM (SpringCM):デジタル契約
  • Ironclad:デジタル契約プラットフォーム
  • Concord:契約管理

リーガルテック:

  • Kira Systems:AI による契約レビュー
  • LawGeex:AI による契約レビュー
  • eBrevia:契約分析

文書管理:

  • SharePoint:コラボレーションとストレージ
  • Box、Dropbox:クラウドストレージ
  • M-Files:インテリジェントな情報管理

よくある課題と解決策

課題:契約の分散

問題:

  • 契約が複数の場所に保管されている
  • 一元管理されたリポジトリがない
  • バージョン管理に問題がある
  • 特定の契約を見つけにくい

解決策:

  • CLM システムを導入する
  • 契約リポジトリを一元化する
  • メタデータのタグ付けとインデックス作成を行う
  • 検索機能を導入する
  • アクセス制御と権限を設定する
  • 定期的に監査と整理を行う
課題:更新管理

問題:

  • 更新期限を逃す
  • 自動更新に気づかない
  • 期限直前に慌てて対応する
  • 交渉力を失う

解決策:

  • 更新リマインダーを自動化する(90/60/30日前)
  • 契約カレンダー/ダッシュボードを用意する
  • 更新ワークフローを整備する
  • 更新前にパフォーマンスレビューを必須にする
  • 標準的な更新スケジュールを設定する
  • 契約満了日を経営陣が把握できるようにする
課題:コンプライアンスの監視

問題:

  • 契約条件を追跡できない
  • 非承認の支出
  • 価格の漏れ
  • SLA 違反に気づかない

解決策:

  • 義務追跡システムを導入する
  • コンプライアンスアラートを自動化する
  • P2P システムと連携する
  • 定期的にコンプライアンス監査を行う
  • サプライヤースコアカードを活用する
  • 罰則を適用するプロセスを整備する
課題:契約交渉の専門知識

問題:

  • 調達部門に法務の専門知識が不足している
  • 一方的な条件を受け入れてしまう
  • 契約条件に一貫性がない
  • リスクにさらされる

解決策:

  • 標準契約テンプレートを用意する
  • 法務チームと連携する
  • 交渉トレーニングを実施する
  • 一般的な条件に関するプレイブックを作成する
  • 複雑な取引では外部の法律顧問を活用する
  • 事前承認済みの条件マトリックスを用意する
課題:価値の実現

問題:

  • 交渉で合意したコスト削減が実現されない
  • 価格上昇を監視できていない
  • 数量のコミットメントを追跡できていない
  • 契約締結後の管理がない

解決策:

  • 契約と実際の支出を追跡する
  • 定期的にビジネスレビューを実施する
  • パフォーマンスダッシュボードを用意する
  • 価値実現のプロセスを整備する
  • 関係者の説明責任を明確にする
  • 契約コンプライアンスチームを設置する

出力形式

契約サマリーレポート

エグゼクティブサマリー:

  • 契約ポートフォリオの総額
  • 有効な契約数
  • 主なリスクと機会
  • 対応項目

ポートフォリオの概要:

指標値
契約総額$45.2M
契約数127
契約平均額$356K
90日以内に期限を迎える契約15件($8.3M)
コンプライアンス率87%
上位10件への集中度62%

対応が必要な契約:

契約 IDサプライヤーカテゴリー金額期限必要な対応
CNT-001Supplier AIT サービス$3.2M2026-03-15更新の判断
CNT-045Supplier B原材料$2.8M2026-04-01価格の再交渉
CNT-078Supplier C物流$1.5M継続中SLA の不遵守
CNT-092Supplier DMRO$0.8M2026-02-28数量の未達

更新パイプライン(今後12か月):

Q1 2026: 15 contracts, $8.3M
  - 8 recommend renew
  - 4 renegotiate
  - 3 competitive bid

Q2 2026: 23 contracts, $12.1M
  - 15 recommend renew
  - 6 renegotiate
  - 2 competitive bid

Q3 2026: 18 contracts, $6.8M
Q4 2026: 12 contracts, $4.5M

コンプライアンス上の問題:

  • 価格差異:価格差異が5%を超える契約が12件

    • 推定年間損失:$450K
    • 対応:契約価格の遵守を徹底する
  • 数量コミットメント:コミットメントの80%未満にとどまる契約が8件

    • リスク:価格引き上げまたは違約金
    • 対応:需要を集約するか、再交渉する
  • SLA 未達:SLA を継続的に達成できていないサプライヤーが5社

    • 対応:違約金を適用し、改善計画を策定する

主な推奨事項:

  1. Q1 に期限を迎える15件の契約更新を優先する
  2. 市場価格を上回る4件の契約について価格を再交渉する
  3. 5社のサプライヤーの SLA 不遵守に対処する
  4. コンプライアンス監視を自動化する
  5. 実績の高いサプライヤーに支出を集約する

確認事項

さらに詳しい情報が必要な場合:

  1. 有効な契約はいくつあり、総額はいくらですか?
  2. CLM システムは導入されていますか?
  3. どのような契約形態ですか?(MSA、SOW、発注書)
  4. 主な懸念事項は何ですか?(コスト削減、コンプライアンス、リスク、更新管理)
  5. 契約は現在どのように保管・管理されていますか?
  6. 近日中に更新または期限を迎える契約はありますか?
  7. コンプライアンスやパフォーマンス上の問題はありますか?
  8. 主な関係者は誰ですか?(調達、法務、財務)
  9. どのような指標や KPI を追跡していますか?
  10. 対応が必要な特定の契約はありますか?

関連スキル

  • supplier-selection:契約前のサプライヤー選定
  • strategic-sourcing:カテゴリー別の調達戦略
  • procurement-optimization:最適な契約条件の検討
  • spend-analysis:契約支出のコンプライアンス
  • supplier-risk-management:契約リスクの評価
  • quality-management:SLA の監視とパフォーマンス管理

コメント